Monday, April 25, 2016

Using Automapper In Your Data Access Code

Who doesn't like Automapper, it makes our life easier. But it is not recommended to use Automapper with entity framework (again you can use Queryable-Extensions  as well).  What Automapper does is, it going through each and every property and mapping your data from source object to the destination object, when we dealing with entity framework (if you using navigation properties) Automapper tries to map navigation properties as well. Of course you can specify the properties you want to map and not to map but that sucks. 

So what we going to do is, skip all the mapping for the navigation properties. How we are going to do that ? yes all the navigation properties are virtual by default. So we can skip mapping  all the virtual properties for that we can write an extension, here it goes ,

 public static class IgnoreVirtualAndUnMappedExtensions
    {
        public static IMappingExpression<TSource, TDestination>
               IgnoreAllVirtual<TSource, TDestination>(
                   this IMappingExpression<TSource, TDestination> expression, string[] includeList)
        {
            var desType = typeof(TDestination);
            var sourceType = typeof(TSource);
            List<string> desTypepropNames = desType.GetProperties().Select(a => a.Name).ToList();
            foreach (var property in sourceType.GetProperties().Where(p =>
                                     p.GetGetMethod().IsVirtual))
            {
                if (!desTypepropNames.Contains(property.Name))
                    expression.ForSourceMember(property.Name, opt => opt.Ignore());
                else if (!includeList.Contains(property.Name))
                    expression.ForMember(property.Name, opt => opt.Ignore());

            }

            return expression;
        }
    } 

(still I'm working on with include list as well but it is not working with circular reference )

So my full AutoMapperHelper class goes like this,


 public static class AutoMapperHelper
    {
        private static IMapper GetMapper<Source, Destination>(string[] includeList)
        {
            if (includeList == null)
                includeList = new string[0];
            var config = new MapperConfiguration(cfg => cfg.CreateMap<Source, Destination>().IgnoreAllVirtual(includeList));

            return config.CreateMapper();
        }
        public static Destination Map<Source, Destination>(Source data, params string[] includeList)
        {
            var mapper = GetMapper<Source, Destination>(includeList);


            return mapper.Map<Destination>(data);
        }
        public static void Map<Source, Destination>(Source data, Destination toData, params string[] includeList) // when mapping single objects
        {
            var mapper = GetMapper<Source, Destination>(includeList);

            toData = mapper.Map(data, toData);
        }
        public static List<Destination> MapToList<Source, Destination>(ICollection<Source> data, params string[] includeList) // when mapping list of objects
        {
            var mapper = GetMapper<Source, Destination>(includeList);

            return mapper.Map<List<Destination>>(data);
        }
        public static void MapToList<Source, Destination>(ICollection<Source> data, ICollection<Destination> todata, params string[] includeList)  // when mapping list of objects
        {
            var mapper = GetMapper<Source, Destination>(includeList);

            todata = mapper.Map(data, todata);
        }
    }


Below is an example of how we can use this helper class, with this scenario I'm getting  a user object by id

EF user class goes like this : 


    public partial class User
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public User()
        {
          
        }
    
        public long Id { get; set; }
        public string first_name { get; set; }
        public string last_name { get; set; }
        public Nullable<int> group_id { get; set; }

        public virtual UserGroup UserGroup { get; set; }
     
    }

DTO user class goes like this :

    public class UserDTO 
    {
      
        public User()
        {
          
        }
    
        public long Id { get; set; }
        public string first_name { get; set; }
        public string last_name { get; set; }
        public int group_id { get; set; }

        public UserGroup UserGroup { get; set; }
     
    }

And the function goes like this : 


 public UserDTO GetUserByID(long id)
        {
            var userDataService = new UserDataService();// data access service
            var user = userDataService.GetUserByID(id); // getting the data (returns EF's User class)
            var dtoUser = AutomaticMapperHelper.Map<DAL.User, UserDTO >(user); 
         // DAL.User =  EF's User class ,User = DTO class for user
            if (dtoUser != null)
                dtoUser .UserGroup = AutomaticMapperHelper.Map<DAL.UserGroup, UserGroup>(user.UserGroup); // we skip the mapping for virtual properties  so we have to map the property again. (this is getting from the user object so we don't have to query the DB again.)
            return dtoUser ;
        }


Here is the data access code for your reference,


 public User GetUserByID(long id)
        {
            using (Unixmo_MainEntities dbcontext = new Unixmo_MainEntities())
            {
                return dbcontext.Users.Include(a=>a.UserGroup).SingleOrDefault(a => a.Id == id);
            }

        }


Hope you find this useful, Happy coding.

Thursday, August 6, 2015

Prevent full post back, when using update panels and AjaxControlToolkit with dynamically loading controls

Update panels which support us in every ASP.NET development are really useful, but when we added AjaxControlToolkit reference to the project and if we are loading dynamic controls that cause a post-back then update panel's behavior is not working as we expected. It should be a compatible issue.

But how to over come this. Let's look at a simple example.

I'm creating a project that's have a repeater controller and it has drop-downs inside with some values and those drop-downs will post-back to the server once the selected index changed (for no reason).
And to show the update panels are working I'm using a <img> and with java-script I will load a Image to that, and then when drop-downs selection change image should not be refreshed.

Here is the full html and the coding to bind the repeater that i'm using. And <img> with file input is inside a update-panel and it's update mode is set to conditional while in the repeater's update panel mode is set to default(to always).


If you look at the reference list AjaxControlToolkit is not added.Now this works perfectly, you can change the drop down index and it will cause a partial post back but still the image will be there.

image is loaded and drop-downs are in default selection.
drop-down selection changed and still the image is there because update panels are working fine


Problems comes when you adding the AjaxControlToolkit  as a reference to the project, suddenly update panels will not work and when you change the drop-down selection, full page will be refreshed and image will be gone.
(No need to use AjaxControlToolkit in your page if you add it to the solution then it will not work)

So what actually went wrong, this is a compatible issue, what happening is those drop downs are not registered into the update panel, cause they are dynamically adding.

How to overcome this :
There are two ways we can overcome this,

  1. When repeater item bound you can find the item and then you can register it as a async post back control, which is the hard way.(ScriptManager.GetCurrent(this).RegisterAsyncPostBackControl(dropdown1);)
  2. The easy way is to change your page's property client id mode to "AutoID". Then all the dynamic controls will assign an id when its's creating and registered with the update-panel.








So that's it, hope you will find this help full one day. Cheers and  Happy Coding.








Sunday, May 10, 2015

How to prevent SQL Injection basics

In my career I have seen couple of ways that coders use when they dealing with databases.

  • One is direct calling of sql command string coded inside of the system. (I also used to use the same way once as I can remember).
  • Using stored procedures to work with the system 
  • Using EF to connect the system and the database { I'm .NET guy :); }

From above methods if you use the first mechanism, because it's easy and you are lazy, your system will be end up with some serious SQL Injection capabilities.


In this case the sql command is send to the SQL server like a string and the it's build inside the SQL server and after that it's executed and provided the result. This process is same like creating a runtime sql command and executing it. Screenshot below is an example of a scenario like that.



 {So who starting coding like this :)  (I did ) ;}

Developer thinks and code for what he sees, In his point of view this is easy and does the work, Let's look at the SQL side;

This is a sample what SQL server will create for the above code. So simply it's correct but what can go wrong is some one can inject sql codes at runtime like below.

In normal scenario  variable  @login_name will equal to a name,
 like : SET @login_name='''chathura''';
And the script genarated will be like this.

SELECT [id] FROM [user_list] 
WHERE [user_name] = 'chathura'  AND [password] = ''

 this is a perfect scenario but what happens someone inserted their user_name like this;

 SET @login_name='''chathura''' +' OR 1=1'

This is gonna hurt big time, because your sql code is generating on the fly, now the result will be like this :

SELECT [id] FROM [user_list] 
WHERE [user_name] = 'chathura' OR 1=1 AND [password] = ''

So it's up to you, you want to enable SQL Injection feature to your application or not :);

Baseline : don not use sql statements like the above, either use store procedures or parameterized query;



{This is my first article so feel free to comment what I have to improve; thanks;}