SQL injection concerns - asp.net

ok i use this route
routes.MapRoute(
"Catalog/Data",
"Catalog/{*data}",
new { controller = "Catalog", action = "Category", data = "" }
);
the Url looks something like http://localhost/Catalog/Computer/Harddrives/internal
Data beening the Computer/Harddrives/internal part
i split it apart and validate the route
here is where my concerns are, atm i do not check for sql injection
i check the route by getting the category from the database using enitity framework
with this function
public Category GetByRoute(string Route)
{
return (from c in XEntity.CategorySet
.Where(c => c.Route == Route)
.Where(c => c.IsEnabled == true)
select c).FirstOrDefault();
}
should i be worried about sql injection with this?

Linq2Sql and the Entity Framework use SQL parameters (except for one edge case) so you'll be fine.
In your case you're actually using Linq over the CategorySet, and linq is executed locally in this case, so it's CategorySet that's touching the database, the where constraints run after (I believe). Again in this case there's no problem.

Related

DbFunctions.TruncateTime LINQ equivalent in EF CORE

I have the following functioning LINQ in my .net app
public ActionResult Index()
{
Dictionary<DateTime?, List<Event>> result;
result = (from events in db.Events.Include("Activity")
where events.IsActive
group events by DbFunctions.TruncateTime(events.DateTimeFrom) into dateGroup
select new { EventDate = dateGroup.Key, Events = dateGroup.ToList() }).ToDictionary(x => x.EventDate, x => x.Events);
return View(result);
}
When I use this in EF Core, I can't use DbFunctions. How can I rewrite this to make it work in Microsoft.EntityFrameworkCore ? I am using SQLite if that makes a difference.
In EF6 DbFunctions.TruncateTime is used instead of DateTime.Date property because for some reason the later is not supported.
In EF Core the former is not needed simply because DateTime.Date now is recognized and translated correctly.
group events by events.DateTimeFrom.Date into dateGroup
Unfortunately there is no documentation (yet) of what is supported, so as a general rule of thumb, always try the corresponding CLR method/property (if any) and check if it translates to SQL and how.
To use DbFunctions in ASP.NET CORE You must create an object.
var DbF = Microsoft.EntityFrameworkCore.EF.Functions;
Now you can easily use it.
var now = DateTime.Now;
int count = db.Tbl.Count(w => DbF.DateDiffDay(now, w.RegisterDate) <= 3);
more detail on github
DbFunctions are not supported yet for EF Core. However you can use "Raw Sql Queries".
You can find documentation of "Raw Sql Queries" here
And also you can track here for DbFunctions for EF Core
EF Core 3.0
I finally found an answer that works. The issue is that I was wanting to Group by Date on a DateTime column in the database.
The key for me was to use the EF.Property function. This allows the class to have the DateTime property which is used for adding that level of data, but below allowed me to then redefine it as a Date. However.. I suspect if I decalared the property on the class, it would have already allowed me to use the .Date function which it was not allowing me todo.
So the solution may rather be to define the property on the model, or use the below to define it in your query.
EF.Property(s, "dt").Date
Full code
var myData = _context.ActivityItems
.GroupBy(a => new { nlid = a.lid, nsd = EF.Property<DateTime>(a, "dt").Date })
.Select(g => new
{
g.Key.nlid,
g.Key.nsd,
cnt = g.Count()
});
I managed to rewrite this in Lambda as well and make it async. Seems to be working the same.
var temp = await _context.Events.Where(x => x.IsActive)
.Include(a => a.Activity)
.GroupBy(x => x.DateTimeFrom.Date)
.Select(g => new { EventDate = g.Key, Events = g.ToList() }).ToDictionaryAsync(x => x.EventDate, x => x.Events);
EF Core 2.0 now supports mapping database functions to static methods on your context.
Check out the section 'Database scalar function mapping' here - https://learn.microsoft.com/en-us/ef/core/what-is-new/
In my case, it is working in this way instead of DbFunctions.TruncateTime or EntityFunctions.TruncateTime-
result = _context.ActivityItems.Where(a => a.DateTimeFrom.Value.Date == paramFilter.DateTimeFrom.Value.Date);
It converts date first in the server side in where condition and then compare with parameter date value-
WHERE CONVERT(date, [a].[DateTimeFrom]) = #__paramFilter_DateTimeFrom_Value_Date_0

NHibernate: adding calculated field to query results

I have inherited an ASP.NET website built on NHibernate, with which I have no experience. I need to add a calculated field based on a column in a related table to an existing query. In SQL, this would be done easily enough using a correlated subquery:
select
field1,
field2,
(select count(field3) from table2 where table2.table1ID = table1.ID) calc_field
from
table1
where
[criteria...]
Unfortunately, of course, I can't use SQL for this. So in reality, I have three related questions:
What is the best way to trace through the web of interfaces, base classes, etc used by NHibernate in order to pinpoint the object where I need to add the field?
Having located that object, what, if anything, has to be done besides adding a public property to the object corresponding to the new field?
Are there any NHibernate-specific considerations with regard to referencing a related object in a query?
Here is the existing code that performs the search:
public INHibernateQueryable<C> Search(ISearchQuery query, string sortField)
{
_session = GetSession();
var c = _session.Linq<C>();
c.Expand("IP");
c.Expand("LL");
c.Expand("LL.Address");
c.Expand("LL.Address.City");
c.Expand("LL.Address.City.State");
c.Expand("LL.Address.City.County");
c.Expand("CE");
c.Expand("IC");
c.Expand("AR");
c.Expand("ER");
c.Expand("Status");
var res = _SearchFilters
.Where(x => x.ShouldApply(query))
.Aggregate(c, (candidates, filter) => (INHibernateQueryable<C>) filter.Filter(candidates, query));
res = SortSearch(res, sortField);
return res;
}
I appreciate any advice from experienced Hibernators.
Thanks,
Mike
If you are only interested in returning a query containing a computed value, you can still call a stored procedure in NHibernate and map the results to a POCO in the same way as you map a table for CRUD operations; obviously read-only instead of updatable.
Have a look at the ISession.CreateSQLQuery method; I can post an example from one of my projects if you need one.

How does Entity Framework decide whether to reference an existing object or create a new one?

Just for my curiosity (and future knowledge), how does Entity Framework 5 decide when to create a new object vs. referencing an existing one? I might have just been doing something wrong, but it seems that every now and then if I do something along the lines of:
using (TestDB db = new TestDB())
{
var currParent = db.Parents.Where(p => p.Prop == passedProp).FirstOrDefault();
if(currParent == null) {
Parent newParent = new Parent();
newParent.Prop = passedProp;
currParent = newParent;
}
//maybe do something to currParent here
var currThing = db.Things.Where(t => t.Prop == passedPropTwo).FirstOrDefault();
currThing.Parent = currParent;
db.SaveChanges();
}
EF will create a new Parent in the database, basically a copy of the currParent, and then set the Parent_ID value of currThing to that copy. Then, if I do it again (as in, if there's already two of those parents), it won't make a new Parent and instead link to the first one. I don't really understand this behavior, but after playing around with it for a while something like:
using (TestDB db = new TestDB())
{
var currParent = db.Parents.Where(p => p.Prop == passedProp).FirstOrDefault();
if(currParent == null) {
Parent newParent = new Parent();
newParent.Prop = passedProp;
currParent = newParent;
}
//maybe do something to currParent here
var currThing = db.Things.Where(t => t.Prop == passedPropTwo).FirstOrDefault();
currThing.Parent = db.Parents.Where(p => p.ID == currParent.ID).First();
db.SaveChanges();
}
seemed to fix the problem. Is there any reason this might happen that I should be aware of, or was there just something weird about the way I was doing it at the time? Sorry I can't be more specific about what the exact code was, I encountered this a while ago and fixed it with the above code so I didn't see any reason to ask about it. More generally, how does EF decide whether to reference an existing item instead of creating a new one? Just based on whether the ID is set or not? Thanks!
If your specific instance of your DBContext provided that specific instance of that entity to you, then it will know what record(s) in the database it represents and any changes you make to it will be proper to that(those) record(s) in the database. If you instantiate a new entity yourself, then you need to tell the DBContext what exactly that record is if it's anything but a new record that should be inserted into your database.
In the special scenario where you have multiple DBContext instances and one instance provides you this entity but you want to use another instance to work with and save the entity, then you have to use ((IObjectContextAdapter)firstDbContext).ObjectContext.Detach() to orphan this entity and then use ((IObjectContextAdapter)secondDbContext).ObjectContext.Parents.Attach() to attach it (or ApplyChanges() if you're also editing it - this will call Attach for you).
In some other special scenarios (your object has been serialized and/or you have self-tracking entities), some additional steps may be required, depending on what exactly you are trying to do.
To summarize, if your specific instance of your DBContext is "aware" of your specific instance of an entity, then it will work with it as if it is directly tied to that specific row in the database.

EF4 throws NotSupported exception when it (imho) shouldn't

OK, this thing just puzzles me.
I have a table, say Users, with columns UserID, Name, etc. Have an object mapped to it using CTP5. So now I want to test it, and do the following:
List<User> users = new List();
// Some init code here, making say 3 users.
using (UsersDbContext)
{
// insert users
}
So far so good, works fine.
Now I want to see if the records match, so I select the users back using the following code.
using (UsersDbContext dbc = UsersDbContext.GetDbContext())
{
List<Users> usersRead = dbc.Users.Where(x => x.ID >= users[0].ID && x.ID <= users[users.Count - 1].ID).ToList();
}
This throws and exception:
System.NotSupportedException: LINQ to
Entities does not recognize the method
'User get_Item(Int32)' method, and
this method cannot be translated into
a store expression.
EF has difficulties seeing that I'm just asking to return an int in Users[0].ID ?
If I replace a call to users[0].ID with a straight int - works fine.
I get what it's trying to do, but I thought it should be pretty easy to check if the method belongs to .NET or Sql Server ?
You are trying to access an indexer in an EF expression, which doesn't translate to an SQL query. You'll have to move the parameters outside the query like this:
int first = users[0].ID;
int last = users[users.Count - 1].ID;
List<Users> usersRead = dbc.Users.Where(x => x.ID >= first && x.ID <= last).ToList();

Best practices re: LINQ To SQL for data access

Part of the web application I'm working on is an area displaying messages from management to 1...n users. I have a DataAccess project that contains the LINQ to SQL classes, and a website project that is the UI. My database looks like this:
User -> MessageDetail <- Message <- MessageCategory
MessageDetail is a join table that also contains an IsRead flag.
The list of messages is grouped by category. I have two nested ListView controls on the page -- One outputs the group name, while a second one nested inside that is bound to MessageDetails and outputs the messages themselves. In the code-behind for the page listing the messages I have the following code:
protected void MessageListDataSource_Selecting(object sender, LinqDataSourceSelectEventArgs e)
{
var db = new DataContext();
// parse the input strings from the web form
int categoryIDFilter;
DateTime dateFilter;
string catFilterString = MessagesCategoryFilter.SelectedValue;
string dateFilterString = MessagesDateFilter.SelectedValue;
// TryParse will return default values if parsing is unsuccessful (i.e. if "all" is selected"):
// DateTime.MinValue for dates, 0 for int
DateTime.TryParse(dateFilterString, out dateFilter);
Int32.TryParse(catFilterString, out categoryIDFilter);
bool showRead = MessagesReadFilter.Checked;
var messages =
from detail in db.MessageDetails
where detail.UserID == (int)Session["UserID"]
where detail.Message.IsPublished
where detail.Message.MessageCategoryID == categoryIDFilter || (categoryIDFilter == 0)
where dateFilter == detail.Message.PublishDate.Value.Date || (dateFilter == DateTime.MinValue)
// is unread, showRead filter is on, or message was marked read today
where detail.IsRead == false || showRead || detail.ReadDate.Value.Date == DateTime.Today
orderby detail.Message.PublishDate descending
group detail by detail.Message.MessageCategory into categories
orderby categories.Key.Name
select new
{
MessageCategory = categories.Key,
MessageDetails = categories.Select(d => d)
};
e.Result = messages;
}
This code works, but sticking a huge LINQ statement like this in the code-behind for a LinqDataSource control just doesn't sit right with me.
It seems like I'm still coding queries into the user interface, only now it's LINQ instead of SQL. However, I feel that building another layer between the L2S classes and the UI would cut back on some of the flexibility of LINQ. Isn't the whole point to reduce the amount of code you write to fetch data?
Is there some possible middle ground I'm not seeing, or am I just misunderstanding the way LINQ to SQL is supposed to be used? Advice would be greatly appreciated.
All your LINQ querys should be in a business logic class, no change from older methodologies like ADO.
If you are a purist you should always return List(of T) from your methods in the business class, in fact, the datacontext should only be visible to the business classes.
Then you can manipulate the list in the user interface.
If you are a pragmatist, you can return a IQueryable object and make some manipulations in the user interface.
Regardless of LINQ, I think that mixing presentation code with database-relaed code is not a good idea. I would create a simple DB abstraction layer on top of LINQ queries. In my opinion LINQ is just a convenient tool, that doesn't have a serious impact on traditional application design.

Resources