Execute Dynamic Entity in Database using Dapper - asp.net

My user send dynamic entity from client-project so, I have to write methods like this
public Task<TUser> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
throw new NotImplementedException();
//string sql = "SELECT * FROM \"IdentityUsers\" WHERE \"NormalizedUserName\" = #NormalizedUserName;";
//using (var connection = _databaseConnectionFactory.CreateConnectionAsync())
//{
// connection.QueryFirstOrDefaultAsync<TUser>(sql,
// new { NormalizedUserName = normalizedUserName });
//}
}
My IDatabaseConnectionFactory class bind ConnectionString like below:
public interface IDatabaseConnectionFactory
{
Task<IDbConnection> CreateConnectionAsync();
}
public class ConnectionFactory : IDatabaseConnectionFactory
{
private readonly string _connectionString;
public ConnectionFactory(string connectionString) => _connectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString));
public async Task<IDbConnection> CreateConnectionAsync()
{
try
{
var connString = new NpgsqlConnection(_connectionString);
await connString.OpenAsync();
return connString;
}
catch
{
throw;
}
}
}
Now, how can I execute following query using generic-type entity TUser
string sql = "SELECT * FROM \"IdentityUsers\" WHERE \"NormalizedUserName\" = #NormalizedUserName;";
using (var connection = _databaseConnectionFactory.CreateConnectionAsync())
{
connection.QueryFirstOrDefaultAsync<TUser>(sql,
new { NormalizedUserName = normalizedUserName });
}
Note: QueryFirstOrDefaultAsync not found under connection here

You aren't awaiting the CreateConnectionAsync. Unfortunately it isn't obvious in this case, because Task<T> is disposable (so the using doesn't complain); try instead:
using (var connection = await _databaseConnectionFactory.CreateConnectionAsync())
{
var user = await connection.QueryFirstOrDefaultAsync<TUser>(sql,
new { NormalizedUserName = normalizedUserName });
}
As a tip: the compiler output (against the original code) helps make this clear:
Error CS1929 'Task<IDbConnection>' does not contain a definition for 'QueryFirstOrDefaultAsync' and the best extension method overload 'SqlMapper.QueryFirstOrDefaultAsync<TUser>(IDbConnection, string, object, IDbTransaction, int?, CommandType?)' requires a receiver of type 'IDbConnection'
which tells us that:
it found some QueryFirstOrDefaultAsync method, but it wasn't usable, because
the target expression is a Task<IDbConnection>, not an IDbConnection
As a side note: it is worth knowing that if you're only doing one operation with the connection, Dapper can deal with opening and closing the connection for you - which can help reduce the number of async/await operations. Consider, for example, if you had a CreateClosedConnection() method that did not open the connection, and thus had no need to be async; the following would still work:
using (var connection = _databaseConnectionFactory.CreateClosedConnection())
{
var user = await connection.QueryFirstOrDefaultAsync<TUser>(sql,
new { NormalizedUserName = normalizedUserName });
}
with Dapper dealing with the await OpenAsync() for you as part of the QueryFirstOrDefaultAsync.

Related

Display all the user's files using Microsoft Graph API not working

I have created one .net website application and i have added dlls and codes same like below reference video.
https://www.youtube.com/watch?v=KNJUrCHv6no&list=PLWZJrkeLOrbZ8Gl8zsxUuXTkmytyiEGSh&index=5
I have created one free Microsoft account with free subscription my id like (xxxx#outlook.com) and i registered my application same in azure same as
https://www.youtube.com/watch?v=k7nnvdNgfOE&list=PLWZJrkeLOrbZ8Gl8zsxUuXTkmytyiEGSh&index=4 this video.
But its not working for me. request.GetAsync().Result takes more time and request time out issue shown. i added my code below. please suggest.
default.aspx
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.Identity.Client;
using Microsoft.Graph;
using Microsoft.Extensions.Configuration;
using Helpers;
using System.Security;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
var config = LoadAppSettings();
if (config == null)
{
iserror.Text = "config error";
return;
}
try
{
var userName = ReadUsername();
var userPassword = ReadPassword();
var client = GetAuthenticatedGraphClient(config, userName, userPassword);
var request = client.Me.Drive.Root.Children.Request();
var results = request.GetAsync().Result;
foreach (var file in results)
{
}
}
catch { iserror.Text = "config file exist. azure error"; }
}
private static SecureString ReadPassword()
{
var securePassword = "xxxxxxx";
SecureString password = new SecureString();
foreach (char c in securePassword)
password.AppendChar(c);
return password;
}
private static string ReadUsername()
{
string username;
username = "xxx#outlook.com";
return username;
}
private static GraphServiceClient GetAuthenticatedGraphClient(IConfigurationRoot config, string userName, SecureString userPassword)
{
var authenticationProvider = CreateAuthorizationProvider(config, userName, userPassword);
var graphClient = new GraphServiceClient(authenticationProvider);
return graphClient;
}
private static IAuthenticationProvider CreateAuthorizationProvider(IConfigurationRoot config, string userName, SecureString userPassword)
{
var clientId = config["applicationId"];
var authority = "https://login.microsoftonline.com/" + config["tenantId"] + "/v2.0";
List<string> scopes = new List<string>();
scopes.Add("User.Read");
scopes.Add("Files.Read");
var cca = PublicClientApplicationBuilder.Create(clientId)
.WithAuthority(authority)
.Build();
return MsalAuthenticationProvider.GetInstance(cca, scopes.ToArray(), userName, userPassword);
}
private static IConfigurationRoot LoadAppSettings()
{
try
{
string asas = HttpContext.Current.Server.MapPath("");
var config = new ConfigurationBuilder()
.SetBasePath(asas)
.AddJsonFile("appsettings.json", false, true)
.Build();
if (string.IsNullOrEmpty(config["applicationId"]) ||
string.IsNullOrEmpty(config["tenantId"]))
{
return null;
}
return config;
}
catch (System.IO.FileNotFoundException)
{
return null;
}
}
}
MsalAuthenticationProvider.cs
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security;
using System.Threading.Tasks;
using Microsoft.Identity.Client;
using Microsoft.Graph;
namespace Helpers
{
public class MsalAuthenticationProvider : IAuthenticationProvider
{
private static MsalAuthenticationProvider _singleton;
private IPublicClientApplication _clientApplication;
private string[] _scopes;
private string _username;
private SecureString _password;
private string _userId;
private MsalAuthenticationProvider(IPublicClientApplication clientApplication, string[] scopes, string username, SecureString password)
{
_clientApplication = clientApplication;
_scopes = scopes;
_username = username;
_password = password;
_userId = null;
}
public static MsalAuthenticationProvider GetInstance(IPublicClientApplication clientApplication, string[] scopes, string username, SecureString password)
{
if (_singleton == null)
{
_singleton = new MsalAuthenticationProvider(clientApplication, scopes, username, password);
}
return _singleton;
}
public async Task AuthenticateRequestAsync(HttpRequestMessage request)
{
var accessToken = await GetTokenAsync();
request.Headers.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
}
public async Task<string> GetTokenAsync()
{
if (!string.IsNullOrEmpty(_userId))
{
try
{
var account = await _clientApplication.GetAccountAsync(_userId);
if (account != null)
{
var silentResult = await _clientApplication.AcquireTokenSilent(_scopes, account).ExecuteAsync();
return silentResult.AccessToken;
}
}
catch (MsalUiRequiredException) { }
}
var result = await _clientApplication.AcquireTokenByUsernamePassword(_scopes, _username, _password).ExecuteAsync();
_userId = result.Account.HomeAccountId.Identifier;
return result.AccessToken;
}
}
}
appsettings.json*
{
"tenantId": "xxxx",
"applicationId": "xxxx"
}
It looks like you're running into the standard deadlock
situation where async method is trying to continue thread which is
blocked by the call to Result. Try using async Task test methods
instead of void .
Note: And especially in user interactions one should be careful of blocking
by using .Result calls on the main thread, as this type of call
can lock-up your application for further user interaction.
Try by avoiding the use of Result in the call.
var results = await request.GetAsync();
and do check if you need to add async to all the methods .
Also check this c# - When querying drive items using Microsoft
Graph- Stack Overflow that is relatable.
Also if above doesn’t resolve , try also to set the Timeout to a
higher value
example:to one hour:
graphServiceClient.HttpProvider.OverallTimeout = TimeSpan.FromHours(1);
Please check these below useful references:
c# - 'await' works, but calling task.Result hangs/deadlocks - Stack
Overflow
How To Access Microsoft Graph API In Console Application
(c-sharpcorner.com)

ASP.NET Web API - call database to insert via async method, but it doesn't work

I have this method:
public async static Task ExecuteSpAndForget(string sp, Location location, params SqlParameter[] parameters)
{
using (SqlConnection conn = await GetConnectionAsync(location))
{
SqlCommand cmd = new SqlCommand(sp, conn);
cmd.Parameters.AddRange(parameters);
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandTimeout = Int32.Parse(ConfigurationManager.AppSettings["CommandTimeout"]);
await cmd.ExecuteNonQueryAsync().ConfigureAwait(false);
}
}
public async static Task<SqlConnection> GetConnectionAsync(Location location)
{
SqlConnection conn = new SqlConnection(ConfigurationManager.AppSettings["ConnectionString" + location]);
await conn.OpenAsync().ConfigureAwait(false);
return conn;
}
And in my log filter I applied to WebApiConfig.cs:
config.Filters.Add(new LogFilter());
And in LogFilter(), I call the database to write log
public static int WriteLog(HttpActionContext actionContext, Exception exception = null)
{
\\logic
var logTask = DatabaseHelper.ExecuteSpAndForget("writelogSP", Location.Log, sqlParams.ToArray());
\\return logic
}
When I am debugging locally, this never writes to the database, when I deployed it to IIS, it sometimes write to the database, sometimes not. I tested it locally in a console app, if I wait several seconds after calling before exit, data can be inserted into the database, otherwise no insert happens if no wait.
Why? How can I use it?
What you are referring to is a background task.
There are different ways of going about it. The simplest one is Task.Run with no await
public static int WriteLog(HttpActionContext actionContext, Exception exception = null)
{
\\logic
// fire and forget, no await
var logTask = Task.Run(async () =>
{
await DatabaseHelper.ExecuteSpAndForget("writelogSP", Location.Log, sqlParams.ToArray());
});
\\return logic;
}
You can check out this link https://blog.stephencleary.com/2014/06/fire-and-forget-on-asp-net.html for a better solution.

CosmosDB C# Gremlin - Getting exception when sending query

Taken from: https://learn.microsoft.com/en-us/azure/cosmos-db/create-graph-dotnet
Am getting a exception on the .wait() part:
NullReferenceException: Object reference not set to an instance of an object.
at Gremlin.Net.Driver.Connection.ReceiveAsync[T]()
at Gremlin.Net.Driver.Connection.SubmitAsync[T](RequestMessage requestMessage)
at Gremlin.Net.Driver.ProxyConnection.SubmitAsync[T](RequestMessage requestMessage)
at Gremlin.Net.Driver.GremlinClient.SubmitAsync[T](RequestMessage requestMessage)
at Gremlin.Net.Driver.GremlinClientExtensions.SubmitAsync[T](IGremlinClient gremlinClient, String requestScript, Dictionary`2 bindings)
Code:
private static string database = "db";
private static string collection = "col";
private static string hostname = "grem-test.gremlin.cosmosdb.azure.com";
public void test()
{
var gremlinServer = new GremlinServer(hostname, 443, enableSsl: true,
username: "/dbs/" + database + "/colls/" + collection,
password: authKey);
var gremlinClient = new GremlinClient(gremlinServer);
var grem = "g.V()";
var t = gremlinClient.SubmitAsync<dynamic>(grem);
t.Wait();
foreach (var result in t.Result)
{
// The vertex results are formed as dictionaries with a nested dictionary for their properties
string output = JsonConvert.SerializeObject(result);
Console.WriteLine(String.Format("\tResult:\n\t{0}", output));
}
It should be:
var task = gremlinClient.SubmitAsync<dynamic>(grem);
task.Wait();
Taken from Gremlin C# Samples:
// Create async task to execute the Gremlin query.
var task = gremlinClient.SubmitAsync<dynamic>(query.Value);
task.Wait();
I started with the sample application where it uses:
private static Task<ResultSet<dynamic>> SubmitRequest(GremlinClient gremlinClient, string query)
{
try
{
return gremlinClient.SubmitAsync<dynamic>(query);
}
catch (ResponseException e)
{
// They have extra stuff here for the request information that isn't relevant
throw;
}
}
I expanded from there and never had any issues besides the occasional exception from trying to run a query while another one was still working. I can only assume that running the queries this way works better than directly calling SubmitAsync().
One other thing I would recommend is double-checking your values for the server parameters just in case.

Async calls in WP7

I have been experimenting with WP7 apps today and have hit a bit of a wall.
I like to have seperation between the UI and the main app code but Ive hit a wall.
I have succesfully implemented a webclient request and gotten a result, but because the call is async I dont know how to pass this backup to the UI level. I cannot seem to hack in a wait for response to complete or anything.
I must be doing something wrong.
(this is the xbox360Voice library that I have for download on my website: http://www.jamesstuddart.co.uk/Projects/ASP.Net/Xbox_Feeds/ which I am porting to WP7 as a test)
here is the backend code snippet:
internal const string BaseUrlFormat = "http://www.360voice.com/api/gamertag-profile.asp?tag={0}";
internal static string ResponseXml { get; set; }
internal static WebClient Client = new WebClient();
public static XboxGamer? GetGamer(string gamerTag)
{
var url = string.Format(BaseUrlFormat, gamerTag);
var response = GetResponse(url, null, null);
return SerializeResponse(response);
}
internal static XboxGamer? SerializeResponse(string response)
{
if (string.IsNullOrEmpty(response))
{
return null;
}
var tempGamer = new XboxGamer();
var gamer = (XboxGamer)SerializationMethods.Deserialize(tempGamer, response);
return gamer;
}
internal static string GetResponse(string url, string userName, string password)
{
if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(password))
{
Client.Credentials = new NetworkCredential(userName, password);
}
try
{
Client.DownloadStringCompleted += ClientDownloadStringCompleted;
Client.DownloadStringAsync(new Uri(url));
return ResponseXml;
}
catch (Exception ex)
{
return null;
}
}
internal static void ClientDownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
ResponseXml = e.Result;
}
}
and this is the front end code:
public void GetGamerDetails()
{
var xboxManager = XboxFactory.GetXboxManager("DarkV1p3r");
var xboxGamer = xboxManager.GetGamer();
if (xboxGamer.HasValue)
{
var profile = xboxGamer.Value.Profile[0];
imgAvatar.Source = new BitmapImage(new Uri(profile.ProfilePictureMiniUrl));
txtUserName.Text = profile.GamerTag;
txtGamerScore.Text = int.Parse(profile.GamerScore).ToString("G 0,000");
txtZone.Text = profile.PlayerZone;
}
else
{
txtUserName.Text = "Failed to load data";
}
}
Now I understand I need to place something in ClientDownloadStringCompleted but I am unsure what.
The problem you have is that as soon as an asynchronous operation is introduced in to the code path the entire code path needs to become asynchronous.
Because GetResponse calls DownloadStringAsync it must become asynchronous, it can't return a string, it can only do that on a callback
Because GetGamer calls GetResponse which is now asynchronous it can't return a XboxGamer, it can only do that on a callback
Because GetGamerDetails calls GetGamer which is now asynchronous it can't continue with its code following the call, it can only do that after it has received a call back from GetGamer.
Because GetGamerDetails is now asynchronous anything call it must also acknowledge this behaviour.
.... this continues all the way up to the top of the chain where a user event will have occured.
Here is some air code that knocks some asynchronicity in to the code.
public static void GetGamer(string gamerTag, Action<XboxGamer?> completed)
{
var url = string.Format(BaseUrlFormat, gamerTag);
var response = GetResponse(url, null, null, (response) =>
{
completed(SerializeResponse(response));
});
}
internal static string GetResponse(string url, string userName, string password, Action<string> completed)
{
WebClient client = new WebClient();
if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(password))
{
client.Credentials = new NetworkCredential(userName, password);
}
try
{
client.DownloadStringCompleted += (s, args) =>
{
// Messy error handling needed here, out of scope
completed(args.Result);
};
client.DownloadStringAsync(new Uri(url));
}
catch
{
completed(null);
}
}
public void GetGamerDetails()
{
var xboxManager = XboxFactory.GetXboxManager("DarkV1p3r");
xboxManager.GetGamer( (xboxGamer) =>
{
// Need to move to the main UI thread.
Dispatcher.BeginInvoke(new Action<XboxGamer?>(DisplayGamerDetails), xboxGamer);
});
}
void DisplayGamerDetails(XboxGamer? xboxGamer)
{
if (xboxGamer.HasValue)
{
var profile = xboxGamer.Value.Profile[0];
imgAvatar.Source = new BitmapImage(new Uri(profile.ProfilePictureMiniUrl));
txtUserName.Text = profile.GamerTag;
txtGamerScore.Text = int.Parse(profile.GamerScore).ToString("G 0,000");
txtZone.Text = profile.PlayerZone;
}
else
{
txtUserName.Text = "Failed to load data";
}
}
As you can see async programming can get realy messy.
You generally have 2 options. Either you expose your backend code as an async API as well, or you need to wait for the call to complete in GetResponse.
Doing it the async way would mean starting the process one place, then return, and have the UI update when data is available. This is generally the preferred way, since calling a blocking method on the UI thread will make your app seem unresponsive as long as the method is running.
I think the "Silverlight Way" would be to use databinding. Your XboxGamer object should implement the INotifyPropertyChanged interface. When you call GetGamer() it returns immediately with an "empty" XboxGamer object (maybe with GamerTag=="Loading..." or something). In your ClientDownloadStringCompleted handler you should deserialize the returned XML and then fire the INotifyPropertyChanged.PropertyChanged event.
If you look at the "Windows Phone Databound Application" project template in the SDK, the ItemViewModel class is implemented this way.
Here is how you can expose asynchronous features to any type on WP7.

Storing connection in a static class (ASP.NET)

Since I'm using Postgresql and can't use LINQ to SQL, I wrote my own wrapper classes.
This is a part of the Student class:
public class Student : User
{
private static NpgsqlConnection connection = null;
private const string TABLE_NAME = "students";
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Password { get; set; }
/// <summary>
/// Reads data from the data reader and moves it to the Student class.
/// </summary>
private static void ReadFields(Student student, NpgsqlDataReader dr)
{
student.Id = Int32.Parse(dr["id"].ToString());
student.FirstName = dr["first_name"].ToString();
student.LastName = dr["last_name"].ToString();
student.Password = dr["password"].ToString();
}
/// <summary>
/// Updates the student
/// </summary>
public void Update()
{
Connect();
Run(String.Format("UPDATE " + TABLE_NAME + " SET first_name='{0}', last_name='{1}', password='{2}' WHERE id={3}", FirstName, LastName, Password, Id));
connection.Dispose();
}
/// <summary>
/// Inserts a new student
/// </summary>
public void Insert()
{
Connect();
Run(String.Format("INSERT INTO " + TABLE_NAME + " (first_name, last_name, password) VALUES ('{0}', '{1}', '{2}')",FirstName, LastName, Password));
connection.Dispose();
}
private static void Run(string queryString)
{
NpgsqlCommand cmd = new NpgsqlCommand(queryString, connection);
cmd.ExecuteScalar();
cmd.Dispose();
}
private static void Connect()
{
connection = new NpgsqlConnection(String.Format("Server=localhost;Database=db;Uid=uid;Password=pass;pooling=false"));
connection.Open();
}
//....
So as you see with every INSERT, DELETE, UPDATE request I'm using Connect() method which connects to the database. I didn't realize how stupid it was before I had to wait for 10 minutes to have 500 rows inserted, as there were 500 connections to the database.
So I decided to move Connection property to a static DB class.
public static class DB
{
private static NpgsqlConnection connection = null;
public static NpgsqlConnection Connection
{
get
{
if (connection == null)
{
connection = new NpgsqlConnection(String.Format("Server=localhost;Database=db;Uid=uid;Password=pass;pooling=false"));
connection.Open();
}
return connection;
}
}
public static void Run(string queryString)
{
NpgsqlCommand cmd = new NpgsqlCommand(queryString, connection);
cmd.ExecuteScalar();
cmd.Dispose();
}
}
It works now! I replaces all Run methods in the Student class with DB.Run
But I want to know if it will work fine with a lot of people online, not me only. I'm not sure how static things work with ASP.NET, maybe it'll eat a lot of memory?..
It is better not to store the connection in a static field. Create the connection object on demand and let the connection pooling manage your connections.
You can enable connection pooling for PostgreSQL and let the pooler manage connections for you. Then you can use either piece of code without worry. Even when you issue multiple open/close commands the pooler will optimize them.
This provides you more flexibility and less worry about a custom management solution, also less code and edge cases. It will depend on the database provider you're using. Something in the connection string like:
Pooling: True or False. Controls
whether connection pooling is used.
Default = True
If you need a database provider that uses connection pooling for Postgres one option is npgsql: Npgsql is a .Net data provider for Postgresql.
It supports connection pooling as described in the docs.
Static classes are singletons. The danger here is what they reference. Because they always stay alive, everything they keep a reference to will not be garbage collected.
To see if this is the case, profile your web servers memory. If it always grows and never shrinks, you may be constantly adding references in a static class which never get collected.
In all honesty though, I'd create it only as needed, and completely avoid all of this.
EDIT:
I mean don't worry about sharing one single connection object across your data access layer. If the provider you're using supports connection pooling, then it will handle the actual connections made to the database. Just use and dispose of your connection objects as needed at any point in your data access layer.
using (var connection = new NpgsqlConnection("your connection string"))
{
//your data access stuff.
}
I know code like this is rather big, bulky, and repetitive, but that's ADO.NET. As long as you isolate these calls in their own classes by creating a data access library/layer, it's very manageable. Hiding the ADO.NET objects in a static class is dangerous, because you'll inevitably forget to close a connection or call Dispose() somewhere. Plus you run the risk of building a large object graph that will never get garbage collected.
public class Dataconnect
{
public static string connstring = ConfigurationSettings.AppSettings["SQLConnection"].ToString();
SqlConnection objcon = new SqlConnection(connstring);
SqlCommand objcmd = new SqlCommand();
public bool Opencon()
{
try {
if (objcon.State == ConnectionState.Closed)
{
objcon.Open();
}
objcmd.Connection = objcon;
return true;
}
catch (Exception ex) { throw new Exception("Error: In Open connesction"); return false; }
}
public bool Closecon()
{
try
{
if (objcon.State == ConnectionState.Open)
{
objcon.Close();
}
objcmd.Dispose();
return true;
}
catch (Exception ex) { throw new Exception("Error: In Close connesction"); return false; }
}
public static int ExecuteQuery(SqlCommand sqlcmd)
{
try
{
Dataconnect objdc = new Dataconnect();
int affectedrecord = 0;
if (objdc.Opencon() == true)
{
sqlcmd.Connection = objdc.objcon;
affectedrecord = sqlcmd.ExecuteNonQuery();
objdc.Closecon();
objdc = null;
return affectedrecord;
}
else { return affectedrecord; }
}
catch (Exception ex) { throw ex;/* new Exception("Error: In ExecuteNonquery");*/ }
}
public static DataTable Generatedatatable(SqlCommand sqlcmd)
{
try { Dataconnect objdc = new Dataconnect();
if (objdc.Opencon() == true)
{
sqlcmd.Connection = objdc.objcon;
SqlDataReader dr;
DataTable objdt = new DataTable();
dr = sqlcmd.ExecuteReader();
objdt.Load(dr);
objdc.Closecon();
objdc = null;
return objdt;
}
else { return null; }
}
catch (Exception Exception) { throw Exception /*new Exception("Error: In Generatedatatable")*/; }
}

Resources