I keep getting an error in application insight when trying to run my Azure function, it works locally on my computer but does not work in Azure. Here is the error message:
System.InvalidOperationException at Microsoft.Azure.WebJobs.Extensions.CosmosDB.CosmosDBTriggerAttributeBindingProvider.ResolveConnectionString
I have added CosmosDbTrigger as a connection string in the settings configurations, so I do not understand what's wrong. The function is triggered when a change is made in the cosmos db so if I change something in the db, and am running the function localy on my pc it works, It's only in the azure portal it keeps failing. The triggers are also working, so I think it's only the function that's the problem.
As there are many other discussions happening with similar issue from this link and check this link and try re checking your configuration file.
internal string ResolveConnectionString(string unresolvedConnectionString, string propertyName)
{
// First, resolve the string.
if (!string.IsNullOrEmpty(unresolvedConnectionString))
{
string resolvedString = _configuration.GetConnectionStringOrSetting(unresolvedConnectionString);
if (string.IsNullOrEmpty(resolvedString))
{
throw new InvalidOperationException($"Unable to resolve app setting for property '{nameof(CosmosDBTriggerAttribute)}.{propertyName}'. Make sure the app setting exists and has a valid value.");
}
return resolvedString;
}
// If that didn't exist, fall back to options.
return _options.ConnectionString;
}
Also, check your _options.ConnectionString value and set that dynamically.
builder.Services.PostConfigure<CosmosDBOptions>(options =>
{
options.ConnectionString = "dynamically set the connection string value here";
});
Related
I've been working with functions with Azure, I've built a very simple Http Function locally by following the example linked here, the only difference is I've defined a User table instead of a Todo table
Everything works as expected locally, I'm able to post and get.
However, when deploying the function and trying to make a POST request I see the following within the logs:
Executed 'User' (Failed, Id=5df9dffe-eedf-4b11-aa10-54fda00992b0, Duration=1ms)System.ArgumentNullException : Value cannot be null. (Parameter 'connectionString')
I've checked the SQL Server to ensure it's accessible by other Azure Services just encase that was causing a problem, but I can confirm it's set to allow.
I have found this question, I've gone through the steps and checked against mine and I can confirm my Function App configuration does have the AzureWebJobsStorage connection string.
I'm not 100% sure why this would be happening due to my lack of knowledge of functions at the moment, have anyone else experience this? if so how did you resolve it?
Update
After further testing, it seems the error is coming from my Startup class,
class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
string connectionString = Environment.GetEnvironmentVariable("SqlConnectionString");
builder.Services.AddDbContext<ApplicationDbContext>(
options => SqlServerDbContextOptionsExtensions.UseSqlServer(options, connectionString));
}
}
Upon deployment, connectionString variable is null.... not sure why though.
Yes, you can not get it because you didn't set it in the configuration settings.
If you want to use the Connection Strings section.
Add the "ConnectionStrings":{} section to your local.settings.json file then add your connection string
{
...
"ConnectionStrings": {
"MyConnectionString": ""
}
}
Then you need to set the connection string in the Settings section of the Function App in the Azure Portal.
The scroll down to the Connection Section
And add a new connection string. Make sure it has the same name as you connection in the local.settings.json file.
Your question isn't 100% clear if this is happening locally (as you refer to local.settings.json) or when deploying. If this occurs when deploying, changing your local.settings.json file will not help, unfortunately.
You will need to add the Application Setting within the Azure Portal (located under Settings -> Configuration -> Application Settings -> New application setting).
You will need to save the application setting, and then restart the Azure Function instance for the changes to reflect.
Check out https://learn.microsoft.com/en-us/azure/azure-functions/functions-how-to-use-azure-function-app-settings?tabs=portal
I have followed the Tutorial and build the basic CF based nodejs applciation to display all BusinessPartners from my S/4HANA on-premise destination.
function getAllBusinessPartners(): Promise<BusinessPartner[]> {
return BusinessPartner.requestBuilder()
.getAll()
.execute({
destinationName: 'MockServer'
});
}
Destination is configured with the Virtual host from cloud connector.
But after deploying to the Cloud Foundry, i get following error for the GET request
{"message":"Service of type destination is not supported! Consider providing your own transformation function when calling destinationForServiceBinding, like this:\n destinationServiceForBinding(yourServiceName, { serviceBindingToDestination: yourTransformationFunction });","level":"warn","custom_fields":{"package":"core","messageContext":"destination-accessor"},"logger":"sap-cloud-sdk-logger","timestamp":"2020-03-09T18:15:41.856Z","msg":"Service of type destination is not supported! Consider providing your own transformation function when calling destinationForServiceBinding, like this:\n destinationServiceForBinding(yourServiceName, { serviceBindingToDestination: yourTransformationFunction });","written_ts":1583777741856,"written_at":"2020-03-09T18:15:41.856Z"}
The application is already bound to the Destination service as well.
Can someone help me here, what went wrong ? or the approach to use destination is different in the new version of Cloud-SDK ?
After lot of attempts, i have made this to work.
My Observations:
Connectivity service is also required to be bound, when using on-premise S4 backend.
There was no errors in the log, i have made certain modification in the code to use async/await
async function getAllBusinessPartners(): Promise<BusinessPartner[]> {
return await BusinessPartner.requestBuilder()
.getAll()
.execute({
destinationName: 'MockServer'
});
}
After this modification, when I hit the GET request, it gave me the following error:
"Failed to get business partners - get request to http://s4h-scc-basic:500/sap/opu/odata/sap/API_BUSINESS_PARTNER/sap/opu/odata/sap/API_BUSINESS_PARTNER failed!"
Could notice that the suffix after the http://domain:port is twice. One I gave in the destination, and the other VDM adds automatically.
Ideally, this error is supposed to be thrown even before adding async/await.
After removing the suffix from the destination, it started to work.
If your request really does error, what you posted here from your logs is most likely not the reason for the failure. We are aware that this message is confusing and will improve it (https://github.com/SAP/cloud-sdk/pull/32).
Can you check whether there are more errors in your logs? Based on the code you posted and the setup you described, this should work. Do you have a binding to the XSUAA service.
I having the same error icrosoft.Azure.Documents.DocumentClientException: Message: {"Errors":["Owner resource does not exist"]} , this is my scenario. When I deployed my webapp to Azure and try to get some document from docDb it throws this error. The docdb exists in azure and contains the document that i looking for.
The weird is that from my local machine(running from VS) this works fine. I'm using the same settings in Azure and local. Somebody have and idea about this.
Thanks
Owner resource does not exist
occurs when you have given a wrong database name.
For example, while reading a document with client.readDocument(..), where the client is DocumentClient instance, the database name given in docLink is wrong.
This error for sure appears to be related to reading a database/collection/document which does not exist. I got the same exact error for a database that did exist but I input the name as lower case, this error appears to happen regardless of your partition key.
The best solution I could come up with for now is to wrap the
var response = await client.ReadDocumentAsync(UriFactory.CreateDocumentUri(database, collection, "documentid"));
call in a try catch, not very elegant and I would much rather the response comes back with some more details but this is Microsoft for ya.
Something like the below should do the trick.
Model myDoc = null;
try
{
var response = await client.ReadDocumentAsync(UriFactory.CreateDocumentUri(database, collection, document));
myDoc = (Model )(dynamic)response.Resource;
}
catch { }
if (myDoc != null)
{
//do your work here
}
That is to get a better idea of the error then create the missing resource so you dont get the error anymore.
A few resources I had to go through before coming to this conclusion:
https://github.com/DamianStanger/DocumentDbDemo
Azure DocumentDB Read Document Resource Not Found
I had the same problem. I found that Visual Studio 2017 is publishing using my Release configuration instead of the Test configuration I've selected. In my case the Release configuration had a different CosmosDB database name that doesn't exist, which resulted in the "owner resource does not exist" error when I published to my Azure test server. Super frustrating and a terrible error message.
It may also be caused by a not found attachment to a document.
This is a common scenario when you move cosmos db contents using Azure Cosmos DB Data Migration tool which moves all the documents with their complete definition but unfortunately not the real attachment content.
Therefore this result in a document that states it has an attachment, and also states the attachment link, but at that given link no attachment can be found because the tool have not moved it.
Now i wrap my code as follow
try{
var attachments = client.CreateAttachmentQuery(attacmentLink, options);
[...]
}
catch (DocumentClientException ex)
{
throw new Exception("Cannot retrieve attachment of document", ex);
}
to have a meaningful hint of what is going on.
I ran into this because my dependency injection configuration had two instances of CosmosClient being created for different databases. Thus any code trying to query the first database was running against the second database.
My fix was to create a CosmosClientCollection class with named instances of CosmosClient
I'm trying to work with Azure Webjobs, I understand the way its works but I don't understand why I need to use two connection strings, one is for the queue for holding the messages but
why there is another one called "AzureWebJobsDashboard" ?
What its purpose?
And where I get this connection string from ?
At the moment I have one Web App and one Webjob at the same solution, I'm experiment only locally ( without publishing anything ), the one thing I got up in the cloud is the Storage account that holds the queue.
I even try to put the same connection string in both places ( AzureWebJobsDashboard,AzureWebJobsStorage) but its throw exception :
"Cannot bind parameter 'log' when using this trigger."
Thank you.
There are two connection strings because the WebJobs SDK writes some logs in the storage account. It gives you the possibility of having one storage account just for data (AzureWebJobsStorage) and the another one for logs (AzureWebJobsDashboard). They can be the same. Also, you need two of them because you can have multiple job hosts using different data accounts but sending logs to the same dashboard.
The error you are getting is not related to the connection strings but to one of the functions in your code. One of them has a log parameter that is not of the right type. Can you share the code?
Okay, anyone coming here looking for an actual answer of "where do I get the ConnectionString from"... here you go.
On the new Azure portal, you should have a Storage Account resource; mine starts with "portalvhds" followed by a bunch of alphanumerics. Click that so see a resource Dashboard on the right, followed immediately by a Settings window. Look for the Keys submenu under General -- click that. The whole connection string is there (actually there are two, Primary and Secondary; I don't currently understand the difference, but let's go with Primary, shall we?).
Copy and paste that in your App.config file on the connectionString attribute of the AzureWebJobsDashboard and AzureWebJobsStorage items. This presumes for your environment you only have one Storage Account, and so you want that same storage to be used for data and logs.
I tried this, and at least the WebJob ran without throwing an error.
#RayHAz - Expanding upon your above answer (thanks)...
I tried this https://learn.microsoft.com/en-us/azure/app-service/webjobs-sdk-get-started
but in .Net Core 2.1, was getting exceptions about how it couldn't find the connection string.
Long story short, I ended up with the following, which worked for me:
appsettings.json, in a .Net Core 2.1 Console app:
{
"ConnectionStrings": {
"AzureWebJobsStorage": "---your Azure storage connection string here---",
"AzureWebJobsDashboard":"---the same connectionstring---"
}
}
... and my Program.cs file...
using System;
using System.IO;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace YourWebJobConsoleAppProjectNamespaceHere
{
public class Program
{
public static IConfiguration Configuration;
static void Main(string[] args)
{
var builder = new ConfigurationBuilder()
.SetBasePath(Path.Combine(AppContext.BaseDirectory))
.AddJsonFile("appsettings.json", true);
Configuration = builder.Build();
var azureWebJobsStorageConnectionString = Configuration.GetConnectionString("AzureWebJobsStorage");
var azureWebJobsDashboardConnectionString = Configuration.GetConnectionString("AzureWebJobsDashboard");
var config = new JobHostConfiguration
{
DashboardConnectionString = azureWebJobsDashboardConnectionString,
StorageConnectionString = azureWebJobsStorageConnectionString
};
var loggerFactory = new LoggerFactory();
config.LoggerFactory = loggerFactory.AddConsole();
var host = new JobHost(config);
host.RunAndBlock();
}
}
}
I followed the tutorial here for building a node.js website on Azure that connects to a SQL-Azure DB:
http://www.windowsazure.com/en-us/develop/nodejs/tutorials/web-site-with-sql-database/
Here's what my .js code looks like:
var sql = require('msnodesql'),
nconf = require('nconf');
exports.authenticate = function(req, res){
var select = "select userID, clientID from users where username_e = '?' AND pwd_e = '?'";
nconf.env().file({ file: 'config.json' });
var conn = nconf.get("SQL_CONN");
console.log(conn);
sql.query(conn, select, [req.param('username'), req.param('password')], function(err, results) {
if(err)
throw err;
console.log(results);
if(results.length == 0) {
// no match
res.redirect('/login?failed=true');
} else {
// authenticated
res.redirect('/start');
}
});
return;
};
But when I run it on my local node.js, I keep getting
"Login failed for user 'mylogin'"
I copied the ODBC connection string directly from the Azure management
site
I replaced {your password here} with my password
I quadruple-checked the username and password are correct (I can successfully log into the management tools, AND I can connect to the DB fine via SQL Server Management Studio from my local)
I added an IP exception for my public IP address for good measure
I tried editing the connection string here and there (changed username to mylogin instead of mylogin#server, tried using the ADO connection string instead)
I ALSO was able to connect successfully in Java using jdbc. Here's the jdbc connection string that worked:
jdbc:sqlserver://xxxmyserver.database.windows.net:1433;DatabaseName=mydb;user=mylogin#xxxmyserver;password=pwd
And here's the node.js ODBC connection string that does not work:
Driver={SQL Server Native Client 10.0};Server=tcp:xxxmyserver.database.windows.net,1433;Database=[mydb];Uid=mylogin#xxxmyserver;Pwd=pwd;Encrypt=yes;Connection Timeout=30;
I am just completely at a loss here, especially since I can connect fine from my local using SSMS. Anyone else run into the same issue?
In case it matters, I am using node.js v0.8.2 (since that's what's on Azure's VMs) and msnodesql v0.2.1
To anyone else stumbling across this and still getting the problem even after taking out the square brackets, there's a flag you need to set in the Azure management portal to enable other Azure services to connect to your Azure SQL database. To add confusion, when you first create it, it adds your IP address to the list, which is why you seem to be able to connect to it fine from your dev machine but not from your Azure instance.
Anyway, to do this, go into the database's settings in your Azure management portal, go to 'allowed IP addresses' and enable 'Windows Azure Services' under allowed services at the bottom.
Try your query without the quotes around the question mark parameters.
var select = "select userID, clientID from users where username_e = ? AND pwd_e = ?";
Quotes are not needed for string (or any type of) parameters. Parameters are sent out of band rather than substituted directly into the query. This is what makes them so much more secure, since they are never evaluated with the SQL.
The problem was with the Database section of my connection string - the square brackets around the database name were causing the problem. The ODBC connection string Azure tells you to use looks like this:
Driver={SQL Server Native Client 10.0};Server=tcp:xxxmyserver.database.windows.net,1433;Database=[mydb];Uid=mylogin#xxxmyserver;Pwd=pwd;Encrypt=yes;Connection Timeout=30;
When instead you need to use this:
Driver={SQL Server Native Client 10.0};Server=tcp:xxxmyserver.database.windows.net,1433;Database=mydb;Uid=mylogin#xxxmyserver;Pwd=pwd;Encrypt=yes;Connection Timeout=30;
Note the lack in square brackets around the database name.
This looks like it's a bug in Azure's management tool that will hopefully go away soon. Hope this saves someone else several hours of debugging.