25 Aralık 2016 Pazar

Facebook Login Asp.Net Mvc

Merhaba,

Bu yazımda projeleriniz için basit ve kullanışlı bir Facebook Login bileşeninden bahsedeceğim. Basit olduğu kadar da kod hakimiyeti üst düzeyde.

Web forms ve Mvc de kullanılabilir, aynı mantık. Ben Mvc örneği üzerinden gideceğim.
Öncelikle Nuget üzerinden aşağıdaki paketi yüklüyorsunuz.


Burası View tarafındaki kodunuz:

                   <form action="/Home/fbInit">
                        <input type="submit" value="Facebook İle Kaydol" class="fbLoginBtn" />

                    </form>

Burası formumuzun gönderildiği Action:

         public ActionResult  fbInit() {
            FbClient fb = new FbClient();
            var Link = fb.CrateLoginUrl().ToString();
            Response.Redirect(Link);
            return null;

        }

Burası callback action'ımız:

public ActionResult fbCallBack(string code) {
            facebookErrorViewModel m = new facebookErrorViewModel();
            try {
                if (code.Length > 10) {
                    FbClient fbc = new FbClient();
                    string token = fbc.GetAccessToken(code);
                    FbProfile fp = fbc.GetUserInfo(token);

                    if (fp.Mail==null) {
                        m.ErrorMsg = "E mail adresinizi paylaşmanız gerekli..";
                        return View(m);
                    } if (fp.Name==null) {
                        m.ErrorMsg = "Ad Soyad bilgisini paylaşmanız gerekli..";
                        return View(m);
                    }
                    return Redirect("/");
                }

            } catch (Exception ex) {
                m.ErrorMsg = "Bir hata oluştu: " + ex.Message;
               return View(m);
            }
      
            return View();

        }

Son olarak bu sonuçları döndüren sınıfımız:

   namespace TestFb.Client.Class {
    public class FbProfile {
        public string ID { get; set; }
        public string Name { get; set; } 
        public string Mail { get; set; }
        public string ProfilePhoto { get; set; }
    }
    public class FbClient {
        string AppID = "App Id";
        string AppSecret = "Secret";

        string CallBackUrl = "https://localhost:44300/Home/fbCallBack";

        string Scope = "email,public_profile";
        //, user_birthday, user_hometown, user_website, offline_access, read_stream, publish_stream, read_friendlists
   

        FacebookClient FacebookIslem = new FacebookClient();
        public Uri CrateLoginUrl() {
            return FacebookIslem.GetLoginUrl(
                                new {
                                    client_id = AppID,
                                    client_secret = AppSecret,
                                    redirect_uri = CallBackUrl,
                                    response_type = "code",
                                    scope = Scope,

                                });
        }

        public dynamic GetAccessToken(string code) {
            dynamic result = FacebookIslem.Post("oauth/access_token",
                                          new {
                                              client_id = AppID,
                                              client_secret = AppSecret,
                                              redirect_uri = CallBackUrl,
                                              code = code
                                          });
            return result.access_token;
        }

        public FbProfile GetUserInfo(dynamic accessToken) {
            var client = new FacebookClient(accessToken);
            var profile = new FbProfile();

            dynamic me =  client.Get("me?fields=id,email,name");
            profile.Name = me.name;
            profile.ID = me.id;
            profile.Mail = me.email;
            profile.ProfilePhoto = string.Format("https://graph.facebook.com/{0}/picture?type=large", profile.ID);
            return profile;
        }
    }

}

Görüldüğü gibi oldukça basit, kodlar da manupule edilmeye oldukça müsait. Facebook app ayarlarını yazmıyorum, eğer bilmiyorsanız önce onu öğrenip sonra bu kod ile çalışmaya başlayın (:

Herkese iyi kodlamalar!

25 Ekim 2016 Salı

Db First mü? Code First mü?

 Merhaba, bu yazımda .Net Entity Framework modellerinden DbFirst ve Code First dezavantajları ve bulduğum çözüm hakkında bir yazı hazırladım.

Db First ile başlarsak, hazır olan bir database ile çalışırken bir kaç wizard yardımı ile tüm db tablolarını auto generated bir şekilde projemize imlement edebiliyoruz. Küçük projeler için daima kullandığım yaklaşım. Ancak proje büyüdükçe ve parçalara ayrıldıkça auto generated bir şekilde oluşan dbContex gittikçe şişmeye başlıyor ve bir süre sonra sürekli contex i silip yeniden generate etmeye geliyor iş,çok can sıkıcı bir amele çözümü.

Code First ü ise ilk önceleri baya bir benimsemiştim. Ancak bu stratejinin de kendine göre dezavantajları vardı. Ben veritabanında büyük harf kullanırım, kod yazarken ise hece başlangıçlarında büyük harf kullanırım. Ancak Code First buna izin vermiyor. Ayrıca modelimin içerisinde veritabanında kullanmaycağım bir özellik eklemek istersem 40 takla atmam gerekiyordu. Veritabanı tarafında oluşturduğum prosedürleri implement ederken birbir türlü hatalar almaya başlamıştım.

Benim şu şekilde bir ORM e ihtiyacım vardı.


  • Kod tarafında oluşturduğum modelleri auto generated contex gibi birşey oluşturmadan veritanabanı tablolarım ile ilişkilendirebilmeliydim.
  • Property isimleri kod tarafında ve db tarafında büyük küçük harf ayrımı olmadan birbirini tanımalıydı.
  • Bir sp yazdığımda, kod tarafında sadece modelini yaptıktan sonra başka bir işlem yapmadan bu sp yi kullanabilmem gerekiyordu.
  • Yani duruma göre istersem db ağırlıklı çalışayım, istersem kod ağırlıklı çalışayım bu ORM'in bunu desteklemesi gerekiyordu.
Sonunda repository patern ile birlikte çok uyumlu olan aşağıdaki ORM'i yazdım. Birkaç senedir de bunu kullanıyorum. 

Öncelikle Container olarak Autofac kullandım ben, diğerlerine göre çok daha uyumlu MVC'e. 
Şimdi adım adım nasıl uygulayacağımıza bakalım.(Bu yalnızca orta ve büyük ölçekli projeler için uygundur). Dependency Container'imizi register ettikten sonra aşağıdaki adımları uyguluyoruz.
Burada dikkat edilmesi gereken konu, tüm tablolarda ID kolonu olmak zorunda ve bu 1. key olmak zorunda.

    [TableSource("TB_BRAND")] -1
    public class BrandModel {
        public int? ID { get; set; }
        public string Name { get; set; }
        public string Dsc { get; set; }
        public string Theme_Css { get; set; }
        public int? ShortNumber { get; set; } -2
        public string PmCode { get; set; }
        public bool Status { get; set; }
    }
1-Buraya modelimizin veritabanında hangi tabloya karşılık geleceğini yazıyoruz.
2-Tüm sayısal veri tipi içeren propertylerimiz nullable olmak zorunda. Property isimlerindeki büyük küçük harf farketmez ancak farklı isimde olmamalı karşılıkları.

Aşağıdaki görsel yukarıda kullandığımız Attribute'miz
Burası da ORM'imizin olduğu sınıf
public class dbBase {
        public static string Cnn = ConfigurationManager.ConnectionStrings["Cnn"].ConnectionString;


        #region Edit Update Delete
        public  int Add(T t) where T : class {
            List<Attribute> attrs = (System.Attribute.GetCustomAttributes(typeof(T))).ToList();
            string table = "";
            foreach (Attribute at in attrs) {
                if (at is TableSource) {
                    table = ((TableSource)at).Name;
                }
            }
            PropertyInfo[] pr = t.GetType().GetProperties();
            List<SqlParameter> prmList = new List<SqlParameter>();
            foreach (PropertyInfo p in pr) {
                if (p.Name == "ID") continue;
                if (!p.PropertyType.ToString().Contains("System")) continue;
                SqlParameter pa = new SqlParameter();
                pa.ParameterName = p.Name;
                pa.Value = t.GetType().GetProperty(p.Name).GetValue(t);
                if (pa.Value == null) continue;
                prmList.Add(pa);
            }
          return  AddSql(table, prmList);
        }
        public void Update(T t) where T : class {
            List<Attribute> attrs = (System.Attribute.GetCustomAttributes(typeof(T))).ToList();
            string table = "";
            foreach (Attribute at in attrs) {
                if (at is TableSource) {
                    table = ((TableSource)at).Name;
                }
            }
            int id = (int)t.GetType().GetProperty("ID").GetValue(t);
            PropertyInfo[] pr = t.GetType().GetProperties();
            List<SqlParameter> prmList = new List<SqlParameter>();
            foreach (PropertyInfo p in pr) {
                if (p.Name == "ID") continue;
                if (!p.PropertyType.ToString().Contains("System")) continue;
                SqlParameter pa = new SqlParameter();
                pa.ParameterName = p.Name;
                pa.Value = t.GetType().GetProperty(p.Name).GetValue(t);
                if (pa.Value == null) continue;
                prmList.Add(pa);
            }
            UpdateSql(table, id, prmList);
        }
        public void Delete(T t) where T : class {
            List<Attribute> attrs = (System.Attribute.GetCustomAttributes(typeof(T))).ToList();
            string table = "";
            foreach (Attribute at in attrs) {
                if (at is TableSource) {
                    table = ((TableSource)at).Name;
                }
            }
            int id = (int)t.GetType().GetProperty("ID").GetValue(t);
            DeleteSql(table, id);
        }
        #endregion


        #region Dynamic Return Methots
        public dynamic GetbyID(int id) where T : class {
            object c = Activator.CreateInstance(typeof(T));
            List<SqlParameter> prmList = new List<SqlParameter>();
            prmList.Add(new SqlParameter("ID", id));
            List<Attribute> attrs = (System.Attribute.GetCustomAttributes(typeof(T))).ToList();
            string table = "";
            foreach (Attribute at in attrs) {
                if (at is TableSource) {
                    table = ((TableSource)at).Name;
                }
            }
            DataTable dt = GetSqlTable(table, prmList);
            PropertyInfo[] p = c.GetType().GetProperties();
            foreach (DataRow dr in dt.Rows) {
                foreach (DataColumn dc in dt.Columns) {
                    object obj = dr[dc];
                    if (obj == DBNull.Value) continue;
                    string propName = dc.ColumnName;
                    if (GetProperty(c, dc.ColumnName) == null) continue;
                    SetProperty(c, propName, obj);
                }
            }
            return c;
        }
        public List GetList(params KeyValuePair<string, object>[] pairs) where T : class {
            List<SqlParameter> prmList = new List<SqlParameter>();
            foreach (KeyValuePair<string, object> key in pairs) {
                prmList.Add(new SqlParameter(key.Key, key.Value));
            }
            List<Attribute> attrs = (System.Attribute.GetCustomAttributes(typeof(T))).ToList();
            string table = "";
            foreach (Attribute at in attrs) {
                if (at is TableSource) {
                    table = ((TableSource)at).Name;
                }
            }
            dynamic c;
            DataTable dt = GetSqlTable(table, prmList);
            PropertyInfo[] p = typeof(T).GetProperties();
            List output = new List();
            foreach (DataRow dr in dt.Rows) {
                c = (T)Activator.CreateInstance(typeof(T));
                foreach (DataColumn dc in dt.Columns) {
                    object obj = dr[dc];
                    if (obj == DBNull.Value) continue;
                    string propName = dc.ColumnName;
                    if (GetProperty(c, dc.ColumnName) == null) continue;
                    SetProperty(c, propName, obj);
                }
                output.Add(c);
            }
            return output;
        }
        public List GetList() where T : class {
            dynamic c;
            List<Attribute> attrs = (System.Attribute.GetCustomAttributes(typeof(T))).ToList();
            string table = "";
            foreach (Attribute at in attrs) {
                if (at is TableSource) {
                    table = ((TableSource)at).Name;
                }
            }
            DataTable dt = GetSqlTable(table);
            PropertyInfo[] p = typeof(T).GetProperties();
            List output = new List();
            foreach (DataRow dr in dt.Rows) {
                c = (T)Activator.CreateInstance(typeof(T));
                foreach (DataColumn dc in dt.Columns) {
                    object obj = dr[dc];
                    if (obj == DBNull.Value) continue;
                    string propName = dc.ColumnName;
                    if (GetProperty(c, dc.ColumnName) == null) continue;
                    SetProperty(c, propName, obj);
                }
                output.Add(c);
            }
            return output;
        }
        #endregion


        #region Private Methots
        private static void SetProperty(Object R, string propName, object value) {
            var obj = R;
            PropertyInfo fi = obj.GetType().GetProperty(propName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
            fi.SetValue(obj, value);
        }
        private static object GetProperty(object R, string propName) {
            Type type = R.GetType();
            object result;
            result = type.GetProperty(
                propName,
                BindingFlags.GetProperty |
                BindingFlags.IgnoreCase |
                BindingFlags.Public |
                BindingFlags.Instance
                );
            return result;
        }
        private DataTable GetSqlTable(string tableName, List<SqlParameter> prms = null) {
            SqlConnection cnn = new SqlConnection(Cnn);
            SqlCommand cmd = new SqlCommand();
            StringBuilder sb = new StringBuilder();
            sb.Append("SELECT * FROM " + tableName +" WITH (NOLOCK) ");
            if (prms != null) {
                if (prms.Count > 0) sb.Append(" WHERE ");
                foreach (SqlParameter pr in prms) {
                    cmd.Parameters.Add(pr);
                    sb.Append(pr.ParameterName + "=@" + pr.ParameterName + " AND ");
                }
                if (prms.Count > 0) sb.Remove(sb.Length - 5, 5);
            }
            cmd.Connection = cnn;
            cmd.CommandText = sb.ToString();
            DataTable dt = new DataTable();
            SqlDataAdapter da = new SqlDataAdapter(cmd);
            da.Fill(dt);
            return dt;
        }
        private int AddSql(string tableName, List<SqlParameter> prms) {
            SqlConnection cnn = new SqlConnection(Cnn);
            SqlCommand cmd = new SqlCommand();
            StringBuilder sb = new StringBuilder();
            sb.Append("INSERT INTO " + tableName + " ( ");
            foreach (SqlParameter prm in prms) {
                cmd.Parameters.Add(prm);
                sb.Append(prm.ParameterName.ToUpper() + ",");
            }
            if (prms.Count > 0) sb.Remove(sb.Length - 1, 1);
            sb.Append(") VALUES (");
            foreach (SqlParameter prm in prms) {
                sb.Append("@" + prm.ParameterName + ",");
            }
            if (prms.Count > 0) sb.Remove(sb.Length - 1, 1);
            sb.Append(")");
            cmd.Connection = cnn;
            cmd.CommandText = Tools.ConvertChar(sb.ToString()) + "; SELECT CAST(scope_identity() AS int)";
            cnn.Open();
            int id = (int)cmd.ExecuteScalar();
            cnn.Close();
            return id;
        }
        private void UpdateSql(string tableName, int id, List<SqlParameter> prms) {
            SqlConnection cnn = new SqlConnection(Cnn);
            SqlCommand cmd = new SqlCommand();
            StringBuilder sb = new StringBuilder();
            sb.Append("UPDATE " + tableName + " SET ");
            foreach (SqlParameter prm in prms) {
                cmd.Parameters.Add(new SqlParameter(Tools.ConvertChar(prm.ParameterName.ToUpper()), prm.Value));
                sb.Append(prm.ParameterName.ToUpper() + "=@" + prm.ParameterName.ToUpper() + ", ");
            }
            if (prms.Count > 0) sb.Remove(sb.Length - 2, 2);
            sb.Append(" WHERE ID=@ID");
            cmd.Parameters.Add(new SqlParameter("@ID", id));
            cmd.Connection = cnn;
            cmd.CommandText = Tools.ConvertChar(sb.ToString());
            cnn.Open();
            cmd.ExecuteNonQuery();
            cnn.Close();

        }
        private void DeleteSql(string tableName, int id) {
            SqlConnection cnn = new SqlConnection(Cnn);
            SqlCommand cmd = new SqlCommand();
            StringBuilder sb = new StringBuilder();
            sb.Append("DELETE FROM " + tableName + " WHERE ID=@ID");
            cmd.Connection = cnn;
            cmd.CommandText = Tools.ConvertChar(sb.ToString());
            cmd.Parameters.Add(new SqlParameter("@ID", id));
            cnn.Open();
            cmd.ExecuteNonQuery();
            cnn.Close();
        }
        #endregion


        #region Stored Procs
        public List GetSpList(string spName, params KeyValuePair<string, object>[] pairs) where T : class {
            SqlConnection cn = new SqlConnection(Cnn);
            SqlCommand cmd = new SqlCommand();
            cmd.Connection = cn;
            StringBuilder sb = new StringBuilder();
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandText = spName;
            foreach (KeyValuePair<string, object> key in pairs) {
                cmd.Parameters.Add(new SqlParameter(key.Key, key.Value));
            }
            SqlDataAdapter da = new SqlDataAdapter(cmd);
            DataTable dt = new DataTable();
            da.Fill(dt);
            List OutList = new List();
            T c;
            foreach (DataRow dr in dt.Rows) {
                c = (T)Activator.CreateInstance(typeof(T));
                PropertyInfo[] pr = c.GetType().GetProperties();
                foreach (DataColumn dc in dt.Columns) {
                    object obj = dr[dc];
                    if (obj == DBNull.Value) continue;
                    string propName = dc.ColumnName;
                    if (GetProperty(c, dc.ColumnName) == null) continue;

                    SetProperty(c, propName, obj);
                }
                OutList.Add(c);
            }
            return OutList;
        }
        public List GetSpResult(params KeyValuePair<string, object>[] pairs) where T : class {
            List<Attribute> attrs = (System.Attribute.GetCustomAttributes(typeof(T))).ToList();
            string spName = "";
            foreach (Attribute at in attrs) {
                if (at is SpSource) {
                    spName = ((SpSource)at).Name;
                }
            }
            List<SqlParameter> ParamList = new List<SqlParameter>();
            foreach (KeyValuePair<string, object> r in pairs) {
                ParamList.Add(new SqlParameter(r.Key, r.Value));
            }
            dynamic c;
            DataTable dt = DAL.executeProc(spName, ParamList.ToArray());
            PropertyInfo[] p = typeof(T).GetProperties();
            List output = new List();
            foreach (DataRow dr in dt.Rows) {
                c = (T)Activator.CreateInstance(typeof(T));
                foreach (DataColumn dc in dt.Columns) {
                    object obj = dr[dc];
                    if (obj == DBNull.Value) continue;
                    string propName = dc.ColumnName;
                    if (GetProperty(c, dc.ColumnName) == null) continue;
                    SetProperty(c, propName, obj);
                }
                output.Add(c);
            }
            return output;
        }
        public static DataTable GetSpTable(string spName, List<SqlParameter> prms = null) {
            SqlConnection cn = new SqlConnection(Cnn);
            SqlCommand cmd = new SqlCommand();
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandText = spName;
            foreach (SqlParameter p in prms) {
                cmd.Parameters.Add(p);
            }
            SqlDataAdapter da = new SqlDataAdapter(cmd);
            DataTable dt = new DataTable();
            da.Fill(dt);
            return dt;
        }
 
        #endregion

    }

Yukarıda görüldüğü gibi, gerektiği yerde DataTable, gerektiği yerde de obje döndürebiliyoruz geriye.

Şimdi IRepository arayüzünü hazırlıyoruz.

     public interface IRepository>{
        int Add(T entity);
        void Update(T entity);
        void Delete(T entity);

        T GetbyID(int id);
        List GetList();
        List GetList(params KeyValuePair<string, object>[] pairs);
    }

Şimdi modelimizin Interface'ini hazırlıyoruz.

   public interface IBrandRepository :IRepository<BrandModel> {
    }

Şimdi de modelimizin Repository sınıfını hazırlıyoruz.

    public class BrandRepository : dbBase, IBrandRepository {
        #region Base
        public int Add(BrandModel entity) {
         return   base.Add<BrandModel>(entity);
        }

        public void Update(BrandModel entity) {
            base.Update<BrandModel>(entity);
        }

        public void Delete(BrandModel entity) {
            base.Delete<BrandModel>(entity);
        }

        public BrandModel GetbyID(int id) {
            return base.GetbyID<BrandModel>(id);
        }

        public List<BrandModel> GetList() {
            return base.GetList<BrandModel>(Pairing.Of("STATUS", true));
        }

        public List<BrandModel> GetList(params KeyValuePair<string,object>[] pairs) {
            return base.GetList<BrandModel>(pairs);
        }

        public List<BrandModel> GetSpList(string spName,params KeyValuePair<string,object>[] pairs) {
            return base.GetSpList<BrandModel>(spName,pairs);
        }
        #endregion
    }

Unutmadan, parametre göndermek için kullandığımız sınıf, ve string karakter problemlerini gidermek için kullandığımız statik metot.

  public class Pairing {
       public static KeyValuePair<string, object> Of(string key, object value) {
           return new KeyValuePair<string, object>(key, value);
       }
    }

        public static string ConvertChar(string str) {
            Encoding iso = Encoding.GetEncoding("Cyrillic");
            Encoding utf8 = Encoding.UTF8;
            byte[] utfBytes = utf8.GetBytes(str);
            byte[] isoBytes = Encoding.Convert(utf8, iso, utfBytes);
            return iso.GetString(isoBytes);
        }

Tabi bu yöntemin de kendine has eksikleri var. Mesela kod içinde karmaşık veritabanı sorgusu yazıyorsanız(bence daha acemisiniz:) yada sp yazmasını sevmiyorsanız bu ORM size göre değil.

Yukarıda görüldüğü gibi çok basit bir şekilde modelimizi hem Code First hem de Db First özelliklerini 

kullanabileceğimiz şekilde yapılandırdık. Ve Auto Generated hiç bir şey kullanmadık. (:

Herkese iyi çalışmalar.