String interpolation in raw SQL methods, How is it possible? - c#

I've just checked the new futures in Entity Framework Core 2.0. There is a really nice feature in it called "String interpolation in raw SQL methods" which is described here.
It says that this code:
var city = "Redmond";
using (var context = CreateContext())
{
context.Customers.FromSql($#"
SELECT *
FROM Customers
WHERE City = {city}");
}
creates this query:
SELECT *
FROM Customers
WHERE City = #p0
It is really strange to me! How FromSql method is written as it has just and input of type string.
How does it understand it is an interpolated string, and then create a parameter #p0 query for it? How can I write a method like FromSql aware of how its string parameters are created?

The way it woks is FromSql( accepts a FormattableString.
When you use $"..." that returns a FormatableString, that class allows you to inspect the passed in string and see all of the { } blocks inside of and the objects they represent. This allows the framework to replace those { } blocks with a placeholder parameter #p0 then create a new parameter using something similar to new SqlParameter("#p0", formatableString.GetArgument(0))

Related

Why does calling a T-SQL function using Entity Framework Core always return -1?

I am using ASP.NET Core and C# if that matters. When I get to the following line in my controller:
var validLogin = context.Database.ExecuteSqlRaw($"SELECT * FROM dbo.[valid_login]('{username}','{password}')");
I will always get -1 returned. I also used ExecuteSqlCommand and got the same result. I have tried creating both table defined and scalar functions and in either case it just returns -1.
The strangest part is that it works in SSMS. When I hit the breakpiont this is the query being sent:
{SELECT * FROM dbo.[valid_login]('test#email.com','password')}
When I run that in SSMS I get the correct result of 1. If it matters here is the latest version of the function. But like I said I get the exact same results with a scalar function.
ALTER FUNCTION valid_login
(#email varchar(1000),
#password varchar(1000))
RETURNS TABLE
AS
RETURN
(SELECT
CASE WHEN (SELECT COUNT(*) FROM [user]
WHERE #email = email_address
AND HASHBYTES('SHA2_512', CONCAT(password_salt, #password)) = password_hash) = 1
THEN 1
ELSE 0
END AS valid)
GO
Clearly, one of two things must be happening. Either Entity Framework Core is changing my SQL code before running it, or I am not using the correct method to get a result from a function. I don't think it's the second one as I do not see a simple context.Database.RunSqlFunction() method or anything like it. And if it's the first one I am not knowledgeable enough to know why that is happening.
Really, I just need to know how to get the result of a T-SQL function in ASP.NET Core using Entity Framework Core. So if you can let me know the simplest way to do that, or what modifications I need to make to make this work, that would be appreciated.
You always get 1 , because it is the number of selected rows.
If you want to get some data from DB you have to use this algorithm:
Create a special class to get data from sp. This class should have all properties that you select in your query string. You don't need to select everything. Just select what you need.
public class ResultData
{
public string Property1 {get;set;}
public string Property2 {get;set;}
.....
.....
}
Add to dbContext ResultData DbSet and config no key like this
public virtual DbSet<ResultData> ResultData { get; set; }
....
modelBuilder.Entity<ResultData>(e =>
{
e.HasNoKey();
});
And this a sample function to get data
public async Task<IEnumerable<ResultData>> GetData(int id, string name)
{
return await _context.Set<ResultData>()
.FromSqlInterpolated($"SELECT Property1, Property2 FROM dbo.[valid_login]('{username}','{password}')")
.ToArrayAsync();
}
I highly recommend you to use parameters instead of string values.

How can I avoid SQL injection in this EF Core query?

Since EF Core does not currently execute group by queries in the database, I'm using the following query to get the job done (InvoiceQuery is a DbQuery type):
long merchantId = 177;
var invTokens = new List<string> {"qasas", "efsac"};
string inClause = string.Join(",", invTokens);
string query = $#"SELECT i.Token, i.Balance, COALESCE(SUM(i.Amount), 0) AS ProcessingAmount
FROM inv.Invoices i
WHERE i.Token IN ({inClause})
AND i.MerchantId = {merchantId}
AND i.Status = {(int)InvoiceStatus.Scheduled}
GROUP BY i.Token, i.Balance";
return await dbContext.InvoicesQuery.FromSql(query).ToListAsync();
The above code runs perfect but I don't like it because it gives me a warning of a 'Possible SQL injection vulnerability'.. I know I can use a #pragma to suppress this warning (that's what I'm currently using).
I have tried passing the query and provide the params to the FromSql method, and that works but the parameter that goes into the IN clause is not getting correctly mapped..
Tried using $"'{string.Join("', '", invTokens)}'" but it didn't work.
Any help would be appreciated
Since EF Core 2.0, you can use a FormattableString, where you can use string interpolation for queries.
String interpolation in FromSql and ExecuteSqlCommand
FormattableString Class
In EF Core 2.0 we added special support for interpolated strings to our two primary APIs that accept raw SQL strings: FromSql and ExecuteSqlCommand. This new support allows C# string interpolation to be used in a 'safe' manner.
The example from the docs:
var city = "London";
var contactTitle = "Sales Representative";
using (var context = CreateContext())
{
context.Set<Customer>()
.FromSql($#"
SELECT *
FROM ""Customers""
WHERE ""City"" = {city} AND
""ContactTitle"" = {contactTitle}")
.ToArray();
}
This will produce:
#p0='London' (Size = 4000)
#p1='Sales Representative' (Size = 4000)
SELECT *
FROM ""Customers""
WHERE ""City"" = #p0
AND ""ContactTitle"" = #p1

Name of Table as a Variabe in SQL (C# parameter)

I have a difficult SQL query, and I don't want to rewrite it on Linq. The problem is: I have two equal tables and I must use one of them in depending on the some condition. So, to pass parameter (the name of table) I use this:
List<Variables> lst = db.Database
.SqlQuery<Variables>(s, new SqlParameter("tableSource", sourceTable))
.ToList();
And My query like this:
SELECT #tableSource.PlanId,
#tableSource.PlanSmall AS PlanImg,
#tableSource.NOb,
...
It Doesn't works, could someone help me, please?
You can't use SqlParameter for this. It is meant to be used to set values for parameters in WHERE clauses for instance. You may consider using a construct like
if (someParam.Equals("thisValue")
{
return "SELECT * FROM thisTable";
} else if (someParam.Equals("thatValue")
{
return "SELECT * FROM thatTable";
}

How to get the parametrized SQL query (with parameters applyed) before execute it in Dapper? [duplicate]

This question already has answers here:
Is there any way to trace\log the sql using Dapper?
(6 answers)
Closed 5 months ago.
I need my sql query with the parameters applyed to log porposes.
private dynamic GetInfo(int cdEmpresa)
{
dynamic info = new ExpandoObject();
StringBuilder sql = new StringBuilder();
sql.AppendLine(" SELECT * from FROM EMPRESA E");
sql.AppendLine(" WHERE cdEmpresa = #cdEmpresa ");
using (IDbConnection cn = GetConnection(cdEmpresa).Connection)
{
Logger.Debug("SQL: " + sql.ToString()); // Does not apply the parameters, obviously
cn.Open();
info = cn.Query<dynamic>(sql.ToString(), new
{
cdEmpresa = cdEmpresa // i need to execute te sql to parametrize it, is there a way to parametrize it first its execution?
}).ToList();
}
return infoCadastro;
}
What you are asking for does not exist at any time while processing your query.
Even when you execute the query, the parameter values are never substituted directly into the SQL command. The whole point of parameterized queries is so code is code, data is data, and the two never cross. This eliminates any possibility of injection attacks, no matter what new language feature, custom escape character, or unicode weirdness you might have to deal with.
On the server side, instead of this:
SELECT * FROM [table] WHERE ID=1234;
It's more as if you run code like this:
DECLARE #ID int;
SET #ID = LoadParameterValueFromClientQueryObject("ID");
SELECT * FROM [table] WHERE ID= #ID;
You're always dealing with a variable, where the value of the variable is held away from the sql language compiler/optimizer until after the command is already compiled into an execution plan.

Dapper LIKE query for MySql safe against Sql Injection?

Is this query safe against sql injection in combination with Dapper?
If not, what would be the correct way to write it under MySql?
Or is there a better version without using concat?
string sql = "SELECT * from user_profile WHERE FirstName LIKE CONCAT("%",#name,"%");"
var result = connection.query<profile>(sql, new {name});
There isn't a problem with that code, but another approach is to perform the the concat at the caller, i.e.
const string sql = "SELECT * from user_profile WHERE FirstName LIKE #name;";
var result = connection.Query<Profile>(sql, new {name = "%"+name+"%"});
This is safe because you are not building SQL dynamically at all. Name is just a normal parameter. Actually, it has nothing to do with Dapper.
Using a string concat here is the right choice. Alternatively you could use the SUBSTRING_INDEX function.

Categories

Resources