Could not GetActiveTransaction - repository

I need to call stored procedure in my App Service. I'm following this tutorial to create a custom repository. But I could not find the Context.Database.
Here is the code:
[UnitOfWork]
public virtual async Task<List<string>> GetUserNames()
{
EnsureConnectionOpen();
using (var command = CreateCommand("GetUsernames", CommandType.storedProcedure))
{
using (var dataReader = await command.ExecuteReaderAsync())
{
var result = new List<string>();
while (dataReader.Read())
{
result.Add(dataReader["UserName"].ToString());
}
return result;
}
}
}
What is the Context.Database and how do I use it?
My application is MVC in .Net4.6.1.
Update 1
I have resolved this issue by inheriting MyApplicationRepositoryBase.
Now I face a new issue when trying to GetActiveTransaction. I don't have any idea about this. What can I do?
Here is the code:
private DbTransaction GetActiveTransaction()
{
return (DbTransaction)_transactionProvider.GetActiveTransaction(new ActiveTransactionProviderArgs
{
{"ContextType", typeof(MyDbContext) },
{"MultiTenancySide", MultiTenancySide }
});
}
Here is the error log:
System.NullReferenceException: Object reference not set to an instance of an object.
at Abp.EntityFramework.EfActiveTransactionProvider.GetActiveTransaction(ActiveTransactionProviderArgs args) in D:\Github\aspnetboilerplate\src\Abp.EntityFramework\EntityFramework\EfActiveTransactionProvider.cs:line 21
Update 2
I tried to comment out the command.Transaction and it worked:
private DbCommand CreateCommand(string commandText, CommandType commandType, params SqlParameter[] parameters)
{
var command = Context.Database.GetDbConnection().CreateCommand();
command.CommandText = commandText;
command.CommandType = commandType;
// command.Transaction = GetActiveTransaction();
foreach (var parameter in parameters)
{
command.Parameters.Add(parameter);
}
return command;
}
I still need to put my code under a Transaction, so I don't want to comment out this line. What should I do?

Now I faced the new issue when trying to get Active Transaction
Add this in PreInitialize method of YourProjectNameDataModule:
Configuration.ReplaceService<IEfTransactionStrategy, DbContextEfTransactionStrategy>(DependencyLifeStyle.Transien‌​t);

Related

How to get a list of all Table names through asp.net API controller

So I want to get a list of all the table names from the database through a controller as an ASP.net API project. I tried to do it through raw sql query without entity and it looked something like this.
public async Task<ActionResult<IList>> GetAllTableNames()
{
using (var context = new DbContext())
{
List<string> results = context.Database.SqlQuery<string>("SELECT name FROM sys.tables").ToListAsync();
}
}
But when I try to use the SqlQuery method I get the error
" 'DatabaseFacade' does not contain a definition for 'SqlQuery' and no accessible extension method 'SqlQuery' ". Anybody that has any idea how to solve this?
First create an Helper method in your controller as shown below
using System.Data.SqlClient;
public async IAsyncEnumerable<string> GetTableNamesAsync()
{
using var connection = new SqlConnection(_dbContext.Database.GetConnectionString());
var command = new SqlCommand("SELECT name FROM sys.tables",connection);
await connection.OpenAsync();
var reader = await command.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
yield return reader.GetString(0);
}
}
Then call in your action Like this
public async Task<IActionResult> Index()
{
var list=new List<string>();
await foreach (var item in GetTableNamesAsync())
{
list.Add(item);
}
return Ok(list);
}

Unable to connect Azure Function App with Database (using .net core 2.1)

Please note (Environment):
Function App: Version 2,
Target Framework: .Net Core 2.1
I am developing a Function App, that will work like Web Api. This Function App will return the data from database tables, also it'll manipulate files in Azure storage(Blob). But I am stuck as I am unable to create ConnectionString from local.settings.json file. Ideally the connection string should be created by default as I followed some tutorials & no where mentioned any extra steps to create default connectionstring value, just need to create it in local.settings.json file.
following is my local.settings.json file content:-
{
"ConnectionStrings": {
"mycs": "data source=servername;initial catalog=dbname;user id=XXXX;password=XXXX;MultipleActiveResultSets=True;"
},
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "",
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"mycs": "data source=servername;initial catalog=dbname;user id=XXXX;password=XXXX;MultipleActiveResultSets=True;"
}
}
following is my HttpTrigger file:
namespace my_api
{
public class myDataContext : DbContext
{
public myDataContext() : base(GetConnectionString()) { }
private static string GetConnectionString()
{
const string providerName = "System.Data.SqlClient";
const string metadata = #"res://*/MYDB.csdl|res://*/MYDB.ssdl|res://*/MYDB.msl";
try
{
string connectString = ConfigurationManager.ConnectionStrings["mycs"].ToString();
// Initialize the connection string builder for the
// underlying provider.
SqlConnectionStringBuilder sqlBuilder = new SqlConnectionStringBuilder(connectString);
// Set the properties for the data source.
//sqlBuilder.IntegratedSecurity = true;
sqlBuilder.MultipleActiveResultSets = true;
// Build the SqlConnection connection string.
string providerString = sqlBuilder.ToString();
// Initialize the EntityConnectionStringBuilder.
EntityConnectionStringBuilder entityBuilder = new EntityConnectionStringBuilder();
//Set the provider name.
entityBuilder.Provider = providerName;
// Set the provider-specific connection string.
entityBuilder.ProviderConnectionString = providerString;
// Set the Metadata location.
entityBuilder.Metadata = metadata;
return entityBuilder.ConnectionString;
}
catch { }
var connectionstring = Environment.GetEnvironmentVariable("mycs");
return connectionstring;
}
public DbSet<flowerset> flowersets
{
get;
set;
}
}
}
Following is the code for :
namespace my_api
{
public static class helpService
{
[FunctionName("helpService_get")]
public static async Task> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequest req,
ILogger log, ExecutionContext context)
{
log.LogInformation("C# HTTP trigger function processed a request helpService_get).");
try {
int page = 0;
int pageSize = 20;
myDataContext entity = new myDataContext();
if (page == 0 && pageSize == 0)
{
return entity.helpsets.ToList();
}
if (pageSize <= 0) { pageSize = 20; }
entity.helpsets.OrderByDescending(x => x.id).Skip((page - 1) * pageSize).Take(pageSize).ToList();
}
catch (Exception exx) {
log.LogInformation("Exception changed (helpService_get): "+exx.Message);
}
return null;
}
}//End of Class
}//End of Namespace
I am getting following error on line entity.helpsets.OrderByDescending(x => x.id).Skip((page - 1) * pageSize).Take(pageSize).ToList();:
Unable to determine the provider name for provider factory of type 'System.Data.SqlClient.SqlClientFactory'. Make sure that the ADO.NET provider is installed or registered in the application config.
According to my test, we can use System.Data.SqlClient to connect Azure SQL in Azure function V2.0. For example
Create an Azure Function with Visual Studio 2019
Install System.Data.SqlClient package(the version I sue is 4.5.1)
Develop the function
local.settings.json file content
"ConnectionStrings": {
"mycs": "Data Source="";Initial Catalog=DotNetAppSqlDb20190826105048_db;User Id="";Password="" "
},
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "",
"FUNCTIONS_WORKER_RUNTIME": "dotnet"
}
}
Code
[FunctionName("Function1")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
try
{
var connectionstring = System.Environment.GetEnvironmentVariable($"ConnectionStrings:mycs"); ;
using (SqlConnection connection = new SqlConnection(connectionstring))
{
connection.Open();
log.LogInformation(" sql login success");
StringBuilder sb = new StringBuilder();
sb.Append("select * from dbo.Todoes");
String sql = sb.ToString();
using (SqlCommand command = new SqlCommand(sql, connection))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
log.LogInformation("{0} {1}", reader.GetInt32(0), reader.GetString(1));
}
}
}
connection.Close();
}
}
catch (SqlException e)
{
Console.WriteLine(e.ToString());
}
return name != null
? (ActionResult)new OkObjectResult($"Hello, {name}")
: new BadRequestObjectResult("Please pass a name on the query string or in the request body");
}
For more details, please refer to the document

Error while trying to unit test a sqlfunction: Unable to verify the expression, invoked 0 times

I'm trying to unit test a sql function for my application, but when i try to verify the method is only called once, it gives an error saying the method isn't called at all. I'm using moq to mock my different contexts and interfaces. The method is located in 'appointmentcontextsql'.
Tried to change what mock was mocking, but then it was unable to cast to different types.
Test:
[TestMethod]
public void CreateAppointment_IsValid()
{
var appointment = new Appointment(61,23,24, DateTime.Today);
using (var mock = AutoMock.GetLoose())
{
mock.Mock<IAppointmentContext>()
.Setup(x => x.CreateAppointment(appointment));
var cls = mock.Create<AppointmentContextSQL>();
cls.CreateAppointment(appointment);
mock.Mock<IAppointmentContext>()
.Verify(x => x.CreateAppointment(appointment), Times.Exactly(1));
}
}
Method to test:
public void CreateAppointment(Appointment appointment)
{
try
{
_conn.Open();
using (SqlCommand cmd = new SqlCommand("CreateAppointment", _conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#questionID", appointment.QuestionId);
cmd.Parameters.AddWithValue("#careRecipientID", appointment.CareRecipientId);
cmd.Parameters.AddWithValue("#volunteerID", appointment.VolunteerId);
cmd.Parameters.AddWithValue("#timestampAppointment", appointment.TimeStamp);
cmd.ExecuteNonQuery();
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
throw;
}
finally
{
_conn.Close();
}
}
Expected the unit test to pass, as i'm just trying to see if the method is called correctly, but the mock.time method tells me it's invoked 0 times.

Create Connection String during installation

I have a Windows Forms application. I want to create a setup file for this application. I used Visual Studio 2012 and SQL Server 12.
I want this setup to work in every new environment.
So, how do I make this connection string dynamic? Can I create a connection string after installation and make it available for every form to access, like in my local machine?
Any kind of source code, video links, explanations or examples will be a great help for me.
I propose to search on the machine for instances of the SQL server, and then in every instance search for the databases. You could setup some logic for example if only one instance is found, and on this instance only database with specific name exists then use this database, but if two or more instances are found, or different database name then preferred is found, show window to user where he can choose the right one.
To find Database instance you could use following method:
private static DataRowCollection SQLDataServers()
{
System.Data.Sql.SqlDataSourceEnumerator instance = System.Data.Sql.SqlDataSourceEnumerator.Instance;
DataTable dt = instance.GetDataSources();
if (dt.Rows.Count>0)
{
return dt.Rows;
}
throw new Exception("No SQL Instance Found");
}
To find tables in the database you can use following method:
private static List<string> GetDatabases(string conString)
{
List<string> list = new List<string>();
using (SqlConnection con = new SqlConnection(conString))
{
con.Open();
using (SqlCommand cmd = new SqlCommand("SELECT name from sys.databases", con))
{
using (IDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
list.Add(dr[0].ToString());
}
}
}
}
return list;
}
To generate connection string you can use nuget package or following methods:
public static string GetSqlDataSourceConnectionString(string dataSource)
{
return GetSQLDataSource(dataSource).ToString();
}
private static SqlConnectionStringBuilder GetSQLDataSource(string dataSource)
{
var r = GetDataSource(dataSource).AddIntegratedSecurity();
return r;
}
private static SqlConnectionStringBuilder GetDataSource(string dataSource)
{
SqlConnectionStringBuilder sqlBuilder = new
SqlConnectionStringBuilder();
sqlBuilder.DataSource = dataSource;
return sqlBuilder;
}
private static SqlConnectionStringBuilder AddIntegratedSecurity(this SqlConnectionStringBuilder connectionStringBuilder)
{
connectionStringBuilder.IntegratedSecurity = true;
return connectionStringBuilder;
}
The method which connects all this elements can be as following:
static void Main(string[] args)
{
var servers=SQLDataServers();
foreach (DataRow item in servers)
{
string serverName = string.Format($"{item.ItemArray[0].ToString()}\\{item.ItemArray[1].ToString()}");
var connectionString = GetSqlDataSourceConnectionString(serverName);
var listOfDB=GetDatabases(connectionString);
}
}

ExecuteNonQueryAsync hangs in MVC app

I have a DAL project I call from my MVC controller. I pass the method a list of objects I want updated. I added break points and it gets to ExecuteNonQueryAsync() and then just hangs. The website keeps "loading" and it never gets to return 1; The query worked before I tried to move it to execute async (you can see where I commented out the execution of the query. I did delete the connection open/close pieces but the query worked fine before this.
Also I updated the code below so I can post it with OBJECT, ListObjects and COL1/COL2 instead of the actual values/object names used.
Thanks in advance!
static async Task<int> NonQuery(System.Data.SqlClient.SqlConnection conn, System.Data.SqlClient.SqlCommand cmd)
{
await conn.OpenAsync();
await cmd.ExecuteNonQueryAsync();
return 1;
}
public static bool updateQuery(List<OBJECT> listObjects)
{
string cnn = System.Configuration.ConfigurationManager.ConnectionStrings["connstring"].ToString();
using (System.Data.SqlClient.SqlConnection mySqlConnection = new System.Data.SqlClient.SqlConnection(cnn))
{
StringBuilder SQLQuery = new StringBuilder();
SQLQuery.AppendLine("UPDATE TABLENAME ");
SQLQuery.AppendLine("SET COL1 = #COL1, ");
SQLQuery.AppendLine("WHERE COL2 = #COL2 ");
//mySqlConnection.Open();
foreach (ObjectType ot in listObjects)
{
System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(SQLQuery.ToString(), mySqlConnection);
cmd.Parameters.Add("#COL1", System.Data.SqlDbType.Int).Value = COL1VALUE;
cmd.Parameters.Add("#COL2", System.Data.SqlDbType.Int).Value = COL2VALUE;
int result = NonQuery(mySqlConnection, cmd).Result;
//cmd.ExecuteNonQuery();
}
//mySqlConnection.Close();
}
As I describe on my blog, this is a common problem when converting your code to async. The proper solution is to replace all Result and Wait calls with await, as such:
public static async Task<bool> updateQueryAsync(List<OBJECT> listObjects)
{
...
int result = await NonQueryAsync(mySqlConnection, cmd);
...
}
static async Task<int> NonQueryAsync(SqlConnection conn, SqlCommand cmd)
I also changed your async methods to end in Async, as specified by the TAP documentation.