Azure Function App C# HTTP Trigger connected to an Azure Database - c#

I try to create a serverless backend for mobile app, following that sample (cheers James) : https://blog.xamarin.com/creating-a-serverless-backend-for-mobile-apps/
Everything works fine for me, until I want to connect my script to a database.
I would like to use that Azure Function App with an Azure Database. For instance, I want my mobile app to call an http request (that triggers the function app), the function app makes a query to the database, and then send an http request back to the mobile.
I tried to follow that video : https://channel9.msdn.com/Series/Windows-Azure-Web-Sites-Tutorials/Create-an-event-processing-Azure-Function?ocid=player
In this video, the developer connects its scripts to a database and performs a query to the database.
It is that step that makes me fail :(
Here is my code :
#r "System.Configuration"
#r "System.Data"
using System.Net;
using System.Configuration;
using System.Data.Sql;
using System.Threading.Tasks;
public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
if (req == null)
log.Info("req is null");
else
log.Info("req is not null");
//log.Info($"C# HTTP trigger function processed a request. RequestUri={req.RequestUri}");
string sConnexionString = "Name=MS_TableConnectionString";
log.Info(sConnexionString);
if (ConfigurationManager.ConnectionStrings[sConnexionString] == null)
log.Info("ConfigurationManager.ConnectionStrings[sConnexionString] is null");
else
log.Info("ConfigurationManager.ConnectionStrings[sConnexionString] is not null");
var str = ConfigurationManager.ConnectionStrings[sConnexionString].ConnectionString;
if (str == null)
log.Info("str is null");
else
log.Info("str is not null");
using (SqlConnection conn = new SqlConnection(str))
{
if (conn == null)
log.Info("conn is null");
else
log.Info("conn is not null");
conn.Open();
var text = "INSERT INTO MyEasyTable(id) values (1)";
using (SqlCommand cmd = new SqlCommand(text, conn))
{
var rows = await cmd.ExecuteNonQueryAsync();
log.Info($"{rows} inserted.");
}
}
// 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);
}
And here is the output log :
2016-10-24T13:19:09.452 Compilation succeeded.
2016-10-24T13:19:13.257 Function started (Id=6ffaade4-58b0-4005-8fe7-7dc06b96c2b7)
2016-10-24T13:19:14.018 req is not null
2016-10-24T13:19:14.018 Name=MS_TableConnectionString
2016-10-24T13:19:14.018 ConfigurationManager.ConnectionStrings[sConnexionString] is null
2016-10-24T13:19:14.018 Function completed (Failure, Id=6ffaade4-58b0-4005-8fe7-7dc06b96c2b7)
2016-10-24T13:19:14.037 Exception while executing function: Functions.HttpTriggerCSharp1. HttpTriggerCSharp1: Object reference not set to an instance of an object.
Thanks to that log, I understand that ConfigurationManager cannot connect to my Azure database :(
I tried many string for sConnexionString :
"Data Source=tcp:BDDSERVERNAME.database.windows.net,1433;Initial Catalog=BDD_NAME;User ID=USER#BDDSERVERNAME;Password=MYPASSWORD"
"MS_TableConnectionString"
"Name=MS_TableConnectionString"
And it never works :(
Please, anybody has an idea ?

Okay I found the answer...
I need to go to the Function App's settings, and add the Connection String in the settings, as mentioned here : Azure Functions Database Connection String
Then, I need to use this line of code :
string sConnexionString = "MS_TableConnectionString";
And it works well !
Thanks to Adrian Hall that allowed me to refine my searches

Related

Programming Power BI datasets with the Tabular Object Model

I try to build Azure Function that getting some data from Power BI dataset,
I do it according to this https://learn.microsoft.com/en-us/analysis-services/tom/tom-pbi-datasets?view=sql-analysis-services-2022
I got error : Exception: Microsoft.AnalysisServices.ConnectionException: The connection string is not valid. ---> System.FormatException: Input string was not in a correct format.
I tried several thing without success.
I have app registration that have full access to workspace and can perform actions by REST API, and the workspace is PPU workspace, so the XMLA endpoint is enabled and all permissions defined.
I tried several connection strings I will list all of them
What should be a connection string or I'm missing something else?
using System.Net;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;
using Microsoft.AnalysisServices.Tabular;
using System;
using RestSharp;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Net.Http;
namespace GetRLSDetails
{
public class Function1
{
private readonly ILogger _logger;
public Function1(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<Function1>();
}
[Function("Function1")]
[Obsolete]
public HttpResponseData Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req)
{
_logger.LogInformation("C# HTTP trigger function processed a request.");
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
string datasetname = Environment.GetEnvironmentVariable("datasetname");
string tenantId = Environment.GetEnvironmentVariable("tenantId");
string appId = Environment.GetEnvironmentVariable("appId");
string appSecret = Environment.GetEnvironmentVariable("appSecret");
string workspaceConnection = $"powerbi://api.powerbi.com/v1.0/{tenantId}/BI Management TEST";
Server server = new Server();
//first version
string connectStringUser = $"Provider = MSOLAP;Data source = {workspaceConnection};initial catalog={datasetname};User ID=app:{appId};Password={appSecret};";
//second version
string connectStringUser = $"Provider = MSOLAP;Data Source ={workspaceConnection};Initial Catalog ={datasetname};User ID =app:{appId}#{tenantId}; Password ={appSecret}; Persist Security Info = True; Impersonation Level = Impersonate";
//third version
string connectStringUser = $"Provider=MSOLAP;Data Source={workspaceConnection};User ID=app:{appId}#{tenantId};Password={appSecret};";
//fourth version
string connectStringUser = $"Data Source={workspaceConnection};User ID=app:{appId}#{tenantId};Password={appSecret};";
//using PBI access token
string connectStringUser = $"Provider=MSOLAP;Data Source={workspaceConnection};UserID=;Password={accessToken};";
server.Connect(connectStringUser);
string response_text = "";
foreach (Database database in server.Databases)
{
response_text= response_text+database.Name+',';
}
response.WriteString(response_text);
return response;
}
Check what you are using for tenantId here.
string workspaceConnection = $"powerbi://api.powerbi.com/v1.0/{tenantId}/BI Management TEST";
In most cases this should be myorg, not anything specific, so I'm not sure why you have a variable there. You can check the entire address in Power BI following the instructions from your link.
If that's not it, I would connect to my Power BI dataset from Excel to build a Connection string that works.
In Excel, select Insert > PivotTable > From Power BI then pick your model. Once you've connected, you can get the connection string from Data > Queries & Connections then click on Connections in the Queries & Connections pane, then right click your connection and select Properties... then switch to the Definitions tab:
Just copy the connection string from here, or maybe it will help you see what's off in what you are trying.

WWW returns "Null" (I think I cant connect to php file) - C# Unity

So I have a script in unity that connects to a MySQL database through a PHP script. The PHP script is working fine, but I can't connect to the PHP file from Unity (C# script). The URL for the WWW is localhost and that is for XAMPP (don't know if that is the problem)
Here is my code:
private string CreateAccountUrl = "http://localhost/CreateAccountScript.php";
IEnumerator CreateAccount()
{
WWWForm Form = new WWWForm();
Form.AddField("Email", CEmail);
Form.AddField("Password", CPassword);
Form.AddField("Username", CUsername);
WWW CreateAccountWWW = new WWW(CreateAccountUrl, Form);
yield return CreateAccountWWW;
if (CreateAccountWWW.error != "Null")
{
Debug.LogError("Cannot Connect to Account Creation!");
}else
{
string CreateAccountReturn = CreateAccountWWW.text;
if (CreateAccountReturn == "Success")
{
Debug.Log(CreateAccountReturn);
CreateAccountMenuHolder.SetActive(false);
ConfirmEmailMenuHolder.SetActive(true);
}else if (CreateAccountReturn == "DB Error")
{
Debug.LogError("DB ERROR!");
}else if (CreateAccountReturn == "Can't connect to DB (connect)")
{
Debug.LogError("Can't connect to DB (connect)");
}else if (CreateAccountReturn == "Can't connect to DB (select)")
{
Debug.LogError("Can't connect to DB (select)");
}
}
}
Please ignore the error debugs, they were only for testing...
If you need my PHP code please say it, because I really need the help.
Thanks in advance!
There probably is no error, but with your current code you'll always think there is one. You have the following error comparison:
if (CreateAccountWWW.error != "Null")
{
Debug.LogError("Cannot Connect to Account Creation!");
}
That is, you're comparing the possible error message against the string "Null". That is not what you want to do. You want to check if your error member is actually null. That is
if (CreateAccountWWW.error != null)
Or, alternatively
if(!string.IsNullOrEmpty(CreateAccountWWW.error))
That should do the trick.

Can not find data from the dbcontext with linq

I am trying to develop a "password reset" functionality. To achieve this, I am generating a guid when a user requests a password reset and send this as an email, with a link to the password reset page, that has the guid as a query string.
The code I have written is below:
Request.QueryString[BusinessLayerConstants.resetPasswordQueryString]) ? Request.QueryString[BusinessLayerConstants.resetPasswordQueryString] : String.Empty;
passwordCode = System.Web.HttpUtility.UrlDecode(passwordCode);
using (DBEntities entities = new DBEntities())
{
User = entities.AspNetUsers.FirstOrDefault(u => u.PasswordReset == passwordCode);
if (User != null)
{
//TODO
}
}
The problem is, linq always returns null. If I run a SQL command in the database with the same guid, I am able to see the data. And the passwordCode variable is getting the right value as well. I have even checked if the passwordCode has some hidden characters because it is coming from the query string; but it is also fine.
I am also using this exact same logic for activation as well. I am passing a guid as a query string, and for activation, I am able to find the data with the following code:
AspNetUser user = entities.AspNetUsers.FirstOrDefault(u => u.ActivationCode == activationCode);
It is not working for the password, I have also tried using .Equals() and .Contains() with no luck.
If anyone has any idea what might be wrong, I would appreciate any help. Thanks.
EDIT:
PasswordReset is just some GUID I generate to pass as a querystring.
Everything is fine when I do this:
But in the code, the code I have written returns null:
Remember that C# is case sensitive you should do like:
Request.QueryString[BusinessLayerConstants.resetPasswordQueryString]) ? Request.QueryString[BusinessLayerConstants.resetPasswordQueryString] : String.Empty;
passwordCode = System.Web.HttpUtility.UrlDecode(passwordCode);
using (DBEntities entities = new DBEntities())
{
User = entities.AspNetUsers.FirstOrDefault(u => u.PasswordReset.ToLower() == passwordCode.ToLower());
if (User != null)
{
//TODO
}
}

How to change sql server connection string dynamically in service stack

I am working on Asp.Net MVC and ServiceStack. I am trying to connect to the sql server database using servicestack ormlite. like
var connectionString = ConfigurationManager.ConnectionStrings["AppDb"].ConnectionString;
container.Register<IDbConnectionFactory>(
new OrmLiteConnectionFactory(connectionString,
SqlServerOrmLiteDialectProvider.Instance)
{
ConnectionFilter = x => new ProfiledDbConnection(x, Profiler.Current)
});
I am able to connect to database, But in my scenario i need to change the connection string dynamically.. That means i need to read the content from Request body and prepare a connection string. In servicestack we configure sql server connection string in AppHost class that means at app start. But i need to set the connection string in my controller. I have tried like place it in session and use that session in ClassLibrary SeviceBase class. But I am unable to use asp.Net sessions in class libraries.How to change sql server connection string dynamically in service stack. so please guide me.
I would change the IDbConnectionFactory to be reused in the scope of the request, instead of the current default, which shares it among all requests.
I have also created a static method (GetDatabaseConnectionFactory()) which returns the instance of OrmLiteConnectionFactory to the IoC container with the custom connection string.
To determine the connection string, I have used a request filter, which simply reads the parameter connectionstring. If it is not set it will use a default value. This value is then
set in the RequestContext.Items collection, which can be accessed by the GetDatabaseConnectionFactory() method.
Remember exposing connection strings this way is dangerous, always check any connection string values thoroughly to ensure they don't contain malicious values. i.e. Ensure they don't try to connect to administrative databases, or a different server, or change default setting overrides etc.
In your AppHost:
ServiceStack V3:
public override void Configure(Container container)
{
container.Register<IDbConnectionFactory>(c => GetDatabaseConnectionFactory()).ReusedWithin(ReuseScope.Request);
RequestFilters.Add((req,res,obj) => {
// Default value
var defaultConnectionString = ConfigurationManager.ConnectionStrings["AppDb"].ConnectionString;
// Get the connection string from the connectionstring parameter, or use default
var dbConnectionString = req.GetParam("connectionstring") ?? defaultConnectionString;
// You should perform some checks here to make sure the connectionstring isn't something it shouldn't be
// ...
// Save the connection string to the HostContext.Instance.Items collection, so we can read it later
HostContext.Instance.Items.Add("ConnectionString", dbConnectionString);
});
}
public static IDbConnectionFactory GetDatabaseConnectionFactory()
{
// Read the connection string from our HostContext Items
var dbConnectionString = HostContext.Instance.Items["ConnectionString"];
if(dbConnectionString == null)
throw new Exception("Connection string has not been set");
// Return the connection factory for the given connection string
return new OrmLiteConnectionFactory(dbConnectionString, SqlServerOrmLiteDialectProvider.Instance) {
ConnectionFilter = x => new ProfiledDbConnection(x, Profiler.Current)
});
}
Usings:
using System;
using Funq;
using ServiceStack.ServiceInterface;
using ServiceStack.ServiceHost;
using ServiceStack.WebHost.Endpoints;
using ServiceStack.OrmLite;
using ServiceStack.Common;
ServiceStack V4:
public override void Configure(Container container)
{
container.Register<IDbConnectionFactory>(c => GetDatabaseConnectionFactory()).ReusedWithin(ReuseScope.Request);
GlobalRequestFilters.Add((req,res,obj) => {
// Default value
var defaultConnectionString = ConfigurationManager.ConnectionStrings["AppDb"].ConnectionString;
// Get the connection string from the connectionstring parameter, or use default
var dbConnectionString = req.GetParam("connectionstring") ?? defaultConnectionString;
// You should perform some checks here to make sure the connectionstring isn't something it shouldn't be
// ...
// Save the connection string to the RequestContext.Items collection, so we can read it later
HostContext.RequestContext.Items.Add("ConnectionString", dbConnectionString);
});
}
public static IDbConnectionFactory GetDatabaseConnectionFactory()
{
// Read the connection string from our Items
var dbConnectionString = HostContext.RequestContext.Items["ConnectionString"];
if(dbConnectionString == null)
throw new Exception("Connection string has not been set");
// Return the connection factory for the given connection string
return new OrmLiteConnectionFactory(dbConnectionString, SqlServerOrmLiteDialectProvider.Instance) {
ConnectionFilter = x => new ProfiledDbConnection(x, Profiler.Current)
});
}
Usings:
using System;
using Funq;
using ServiceStack;
using ServiceStack.Data;
using ServiceStack.OrmLite;
using ServiceStack.OrmLite.Sqlite;

How to read an SQL query generated by Dapper?

I have a standard code:
public IEnumerable ExperimentSelect(object parameters)
{
using (var connection = new SqlConnection(ConnectionString))
{
connection.Open();
var dynamicparam = new DynamicParameters(parameters);
var rows = connection.Query("[dbo].[ptbSapOrderSelect]", dynamicparam,
commandType: CommandType.StoredProcedure);
if (rows.Any())
TotalRows = ((long)rows.ToList()[0].TotalRows);
return rows;
}
}
How to automate saving queries generated by Dapper to the file using eg NLog? I am thinking of getting source of SQL query as shown in the SQL Server Profiler.
I managed to make this work in an ASP.Net MVC app using MiniProfiler.
First, configure MiniProfiler as per the docs. Make sure that you are wrapping your SqlConnection inside a ProfiledDbConnection.
Note that you don't need to enable the visual widget for this to work, just ensure that a profile is started before, and ended after, each request.
Next, in global.asax.cs where the profile for that request is stopped, amend it as follows:
protected void Application_EndRequest()
{
// not production code!
MiniProfiler.Stop();
var logger = NLog.LogManager.GetCurrentClassLogger();
var instance = MiniProfiler.Current;
if (instance == null) return;
var t = instance.GetSqlTimings();
foreach (var sqlTiming in t)
{
logger.Debug(sqlTiming.CommandString);
}
}
This literally dumps the SQL command executed, but there is a lot more information included in the model if you want to report more advanced information.

Categories