Entity Framework 4.1 SQL Injection - entity-framework-4.1

I am developing an ASP.Net MVC 3 application using Entity Framework 4.1. For one of queries I am taking advantage of the SqlQuery method on the DbSet class which enables me to execute a raw SQL query that returns an entity list.
I have a method within my Service class, see below, where I write the raw sql and pass in two parameters, shiftID and shiftDateID.
public IList<User> GetAvailableLocums(int shiftID, int shiftDateID)
{
var query = #"set language 'British'
SELECT *
FROM [Shift]
WHERE shiftID = #p0
AND shiftDateID = #p1";
return _UoW.User.GetWithRawSql(query, shiftID, shiftDateID).ToList();
}
I then call the following method in my Repository class, see below,
public IEnumerable<TEntity> GetWithRawSql(string query, params object[] parameters)
{
return dbSet.SqlQuery(query, parameters).ToList();
}
I am worried that this might be open to a SQL Injection attack. If so, does anyone know how I can parametrize my two parameters?
Thanks for your help.

Have you seen this http://msdn.microsoft.com/en-us/library/bb738521.aspx? Second code block..

Related

Execute stored procedure in mvc through EnterpriseLibrary

I am tyring to develop a sample project in mvc. In this, i tried to get the userlist from database (mysql). i am using enterprise library dll to set the database connectivity.
public IEnumerable<UserViewModel> GetUserList()
{
DatabaseProviderFactory factory = new DatabaseProviderFactory();
Database db = factory.Create("MySqlConnection");
DbCommand dbc = db.GetStoredProcCommand("uspGetUserList");
dbc.CommandType = CommandType.StoredProcedure;
return db.ExecuteDataSet(dbc);
}
i know the executedataset is to execute only dataset type... i want the command that execute IEnumerable type.....
thank you
If you want to return an IEnumerable type without manually constructing it (either from a DataSet or an IDataReader) then you can use accessors.
In your case your could would look like this:
public IEnumerable<UserViewModel> GetUserList()
{
DatabaseProviderFactory factory = new DatabaseProviderFactory();
Database db = factory.Create("MySqlConnection");
IEnumerable<UserViewModel> results = db.ExecuteSprocAccessor<UserViewModel>("uspGetUserList");
return results;
}
This assumes that the UserViewModel can be mapped from the stored procedure result set (e.g. column names are the same name as the property names). If not, then you would need to create a custom mapper. See Retrieving Data as Objects from the Developer's Guide for more information about accessors.

Unable to cast object of type nullable(of object) using entity framework

I'm currently using a scenario of MVC 4 WebAPI w Entity Framework database first modelling. Within my apicontroller it is giving me an error of:
An error has occurred.
Unable to cast object of type
'WhereSelectEnumerableIterator2[VB$AnonymousType_42[System.Nullable1[System.Guid],System.Collections.Generic.IEnumerable1[CK5.Airline]],VB$AnonymousType_51[System.Nullable1[System.Guid]]]'
to type 'System.Collections.Generic.IEnumerable1[CK5.Airline]'.
</ExceptionMessage>
<ExceptionType>System.InvalidCastException</ExceptionType>
<StackTrace> at lambda_method(Closure , Object , Object[] ) at
System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass13.<GetExecutor>b__c(Object
instance, Object[] methodParameters) at
System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object
instance, Object[] arguments) at
System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func1
func, CancellationToken cancellationToken)
Public Class AirlineController
Inherits ApiController
' GET api/Airline
Function GetAirlines() As IEnumerable(Of Airline)
Using db As New DefaultEntities
Return From p In db.Airlines.AsEnumerable Order By {p.Name} Group By ParentID = p.ParentID Into parentIDGroup = Group Select New With {.ParentID = ParentID}
End Using
End Function
End Class
Within my entity model object the ParentID is a nullable(of guid) type and I believe causing the problem. I've had this working before using a Linq2Sql scenerio, but with the update, this is giving me a problem. I don't believe it's a problem with the web api structure, just w entity framework. Where am I going wrong?
i fixed it. 1) For some reason EF doesn't like to use the statement Using db as New DBContext, it closes the connection before use I think. 2) I'm not sure why either, but it also doesn't like using lambda statements. So it didn't like the Order By or Group By statement. I'll have to look in to that. 3) problem was a bit unrelated, but as this was being a database first EF, I had also put in the globabl.asax this statement: Database.SetInitializer(New DropCreateDatabaseIfModelChanges(Of DefaultEntities)()). Thinking it would update the model or database based on changes. It lied to me. =/

Using Dapper with SQL Spatial Types as a parameter

I've got a system which basically has to do a query like this:
SELECT * FROM MyTable WHERE #parameter.STIntersects(MyGeometryColumn)
This is quite simple to do when using vanilla SQL parameters, you just have to create your parameter in a non-typical way (where the builder variable is a SqlGeometryBuilder which I use to create a rectangle):
command.Parameters.Add(new SqlParameter
{
UdtTypeName = "geometry",
Value = builder.ConstructedGeometry,
ParameterName = "#paremeter"
});
Now, When I try to do this using dapper, I get an error that it can't figure out how to use this as a parameter. Anyone who has got this working, or any pointers on how to enable this? I do have a workaround, but that involves using the string representation and converting that to a geometry type in my SQL query. I really don't want that.
To answer the comment, the error I'm getting is 'The member Parameter of type Microsoft.SqlServer.Types.SqlGeometry cannot be used as a parameter value'. In other words, dapper doesn't know how to deal with a SqlGeometry object as a parameter.
The key to implementing weird and wonderful DB specific params all boils down to SqlMapper.IDynamicParameters
This simple interface has a single endpoint:
public interface IDynamicParameters
{
void AddParameters(IDbCommand command);
}
Dapper already has a DB generic implementation of this interface called: DynamicParameters which allows you to handle output and return values.
To emulate this spatial stuff I would try something like:
public class SpatialParam : SqlMapper.IDynamicParameters
{
string name;
object val;
public SpatialParam(string name, object val)
{
this.name = name;
this.val = val;
}
public void AddParameters(IDbCommand command, SqlMapper.Identity identity)
{
var sqlCommand = (SqlCommand)command;
sqlCommand.Parameters.Add(new SqlParameter
{
UdtTypeName = "geometry",
Value = val,
ParameterName = name
});
}
}
Usage:
cnn.Query("SELECT * FROM MyTable WHERE #parameter.STIntersects(MyGeometryColumn)",
new SpatialParam("#parameter", builder.ConstructedGeometry));
This simple implementation of the interface handles only a single param, but it can easily be extended to handle multiple params, either by passing in from the constructor or adding a helper AddParameter method.
If you don't mind modifying Dapper at its core then you can use what I've done... https://gist.github.com/brendanmckenzie/4961483
I modified Dapper to accept Microsoft.SqlServer.Types.SqlGeography parameters.
Dapper.EntityFramework 1.26 has support for DbGeography
Dapper 1.32 has inbuilt support for SqlGeography
Dapper 1.33 has inbuilt support for SqlGeometry
Dapper.EntityFramework 1.33 has inbuilt support for DbGeometry
Dapper 1.34 has inbuilt support for SqlHierarchyId
So with the latest libraries; it should simply work.

Advice on filtering data and code reuse with Onion Architecture

Here are my questions and then I'll give you the background for them:
I would prefer to use Method 2 as my application design, so is there a way to provide filtering like Method 1 without introducing references to non-business code and without allowing access to the database model in the Core project?
How do you handle code reuse? The namespaces for each object are something like Project.Core.Domain or Project.Core.Services, but if feels weird making the namespace something like CompanyName.Core.Domain when it is not stored in that project. Currently, I'm copying the source code files and renaming namespaces to handle this, but I'm wondering if there is an organizational way to handle this or something else I hadn't thought of?
Technologies I'm using:
ASP.NET MVC 3
Linq-to-SQL
StructureMap
Moq
MSTest
Method 1:
Here's how I used to setup my web projects:
The Data project would contain all repositories, and Linq data contexts. In a repository, I would return a collection of objects from the database using IQueryable.
public IQueryable<Document> List()
{
return from d in db.Documents
select d;
}
This allowed me to setup filters that were static methods. These were also stored in the Data project.
public static IQueryable<Document> SortByFCDN(this IQueryable<Document> query)
{
return from d in query
orderby d.ID
select d;
}
In the service layer, the filter could be applied like this.
public IPagedList<Document> ListByFCDN(int page, IConfiguration configuration)
{
return repository.List().SortByFCDN().ToPagedList(page, configuration.PageSize, configuration.ShowRange);
}
Therefore, the repository would only have to provide a ListAll method that returned all items as an IQueryable object and then the service layer would determine how to filter it down before returning the subset of data.
I like this approach and it made my repositories cleaner while leaving the bulk of the code in the services.
Method 2
Here's how I currently setup my web projects:
Using the Onion Architecture:
Core: Contains business domain model, all interfaces for the application, and the service class implementations.
Infrastructure: Contains the repository implementations, Linq data contexts, and mapping classes to map the Linq database model to the business model.
Since I'm separating my business code from database code, I do not want to add references in the Core project to things like Linq to gain access to IQueryable. So, I've had to perform the filtering at the repository layer, map the database model to the domain model, and then return a collection of domain objects to the service layer. This could add additional methods into my repositories.
This is what I ended up doing:
1) Created a filtering enum object in the Core project.
public enum FilterType
{
SortFCDN
}
2) In the service class (also within the Core project), do something like:
public IPagedList<Document> ListByFCDN(int page)
{
Dictionary<FilterType, object> filters = new Dictionary<FilterType, object>();
filters.Add(FilterType.SortFCDN, "");
return repository.List(page, filters);
}
3) In the repository (under the Infrastructure project):
public IPagedList<Document> List(int page, Dictionary<FilterType, object> filters)
{
//Query all documents and map to the model.
return (from d in db.DbDocuments
select d).Filter(filters).Map(
page,
configuration.Setting("DefaultPageSize", true).ToInt(),
configuration.Setting("DefaultShowRange", true).ToInt());
}
4) Create a filters class in the Infrastructure project:
public static class DocumentFilters
{
public static IQueryable<DbDocument> Filter(this IQueryable<DbDocument> source, Dictionary<FilterType, object> filters)
{
foreach (KeyValuePair<FilterType, object> item in filters)
{
switch (item.Key)
{
case FilterType.SortFCDN:
source = source.SortFCDN();
break;
}
}
return source;
}
public static IQueryable<DbDocument> SortFCDN(this IQueryable<DbDocument> source)
{
return from d in source
orderby d.ID
select d;
}
}
The service layer (Core project) can then decide what filters to apply and pass those filters to the repository (Infrastructure project) before the query executes. Multiple filters can be applied as long as only one per FilterType is applied.
The filters dictionary can hold the type of filter and any value/object that needs to be passed into the filter. New filters can easily be added as well.

LINQ to SQL Translation

Depending on how I map my linq queries to my domain objects, I get the following error
The member 'member' has no supported translation to SQL.
This code causes the error:
public IQueryable<ShippingMethod> ShippingMethods {
get {
return from sm in _db.ShippingMethods
select new ShippingMethod(
sm.ShippingMethodID,
sm.Carrier,
sm.ServiceName,
sm.RatePerUnit,
sm.EstimatedDelivery,
sm.DaysToDeliver,
sm.BaseRate,
sm.Enabled
);
}
}
This code works fine:
public IQueryable<ShippingMethod> ShippingMethods
{
get
{
return from sm in _db.ShippingMethods
select new ShippingMethod
{
Id = sm.ShippingMethodID,
Carrier = sm.Carrier,
ServiceName = sm.ServiceName,
EstimatedDelivery = sm.EstimatedDelivery,
DaysToDeliver = sm.DaysToDeliver,
RatePerUnit = sm.RatePerUnit,
IsEnabled = sm.Enabled,
BaseRate = sm.BaseRate
};
}
}
This is my testmethod I am testing with:
[TestMethod]
public void Test_Shipping_Methods() {
IOrderRepository orderRepo = new SqlOrderRepository();
var items = orderRepo.ShippingMethods.Where(x => x.IsEnabled);
Assert.IsTrue(items.Count() > 0);
}
How does the way in which I instantiate my object affect the linq to sql translation?
Thanks
Ben
It tries to map the entire linq query to SQL, including all method and property calls. The only exceptions are the object initializer syntax (both for anonymous as named types) and extension methods that themselves map to SQL (.Count() for instance).
Short story: you cannot use non-default constructors with Linq to SQL or Entity Framework.
The most significant issue here is that you are mixing predicate and projection semantics.
Once you project (i.e. with select), it is no longer safe to use the Where extension until you materialize the results with ToList(), ToArray() or similar. The second case just happens to work because the projection is completely transparent - all you are doing is property assignments, and to the same class. Constructors don't fall into this category; as the error message says, there's no equivalent representation of a constructor invocation in SQL Server.
Why do you need to do this projection anyway? The whole property could be replaced with just:
return _db.ShippingMethods.AsQueryable();