نظرات مطالب
نحوه ایجاد یک اسلایدشو به صورت داینامیک
با سلام ..
من همه چیز را همان طوری که شما گفتید انجام دادم ولی نمی‌دونم چرا اجرا نی کنه ..بعد از لود صفحه یک لحظه نشون میده بعد فقط فلش که برای حرکت تصویر است نشون میده و اون هم در گوشه بالای صفحه :
این هم کد :::
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Web;


public class GallerySite
{
    int iD;

    public int ID
    {
        get { return iD; }
        set { iD = value; }
    }
    string imagePath;

    public string ImagePath
    {
        get { return imagePath; }
        set { imagePath = value; }
    }
    string imageText;

    public string ImageText
    {
        get { return imageText; }
        set { imageText = value; }
    }
    public List<GallerySite> GetImage()
    {
        List<GallerySite> _Gallery = new List<GallerySite>() { };
        SqlConnection cnn = new SqlConnection("Data Source=.;Initial Catalog=RoshanZamirDataBase;Integrated Security=True");
        cnn.Open();
        SqlCommand cmd = new SqlCommand("Select * From Gallery", cnn);
        SqlDataReader datareadfewr = cmd.ExecuteReader();
        if (datareadfewr.HasRows)
        {
            while (datareadfewr.Read())
            {
                _Gallery.Add(new GallerySite()
                {
                    ID = Convert.ToInt32(datareadfewr["ID"]),
                    ImagePath = (string)datareadfewr["ImagePath"],
                    ImageText=(string)datareadfewr["ImageText"]
                });
            }
        }
        return _Gallery;
    }
}

.................................................................................................................................




    <link href="orbit-1.2.3.css" rel="stylesheet" />
    <script src="jquery-1.8.3.min.js"></script>
    <script src="jquery.orbit-1.2.3.min.js"></script>
    <script type="text/javascript">
        $(function () {
            $.ajax({
                url: "Handler.ashx",
                contentType: "application/json; charset=utf-8",
                success: function (data) {
                    $.each(data, function (i, b) {
                        var str = '<img src="' + b.ImagePath + '" alt="' + b.ImageText + '"/>';
                        $("#featured").append(str);
                    });
                    $('#featured').orbit();
                },
                dataType: "json"
            });
        });
    </script>




...........................................................................................................................

Handler :



public class Handler : IHttpHandler {
    
    public void ProcessRequest (HttpContext context) {
        var _Gallery = new GallerySite();
        var List = _Gallery.GetImage();
        string str = JsonConvert.SerializeObject(List);
        context.Response.Write(str);          
    } 
    public bool IsReusable {
        get {
            return false;
        }
    }
}


مطالب
پیاده سازی Row Level Security در Entity framework
در این مقاله قصد داریم به صورت عملی row level security را در زبان #C و Entity framework پیاده سازی نماییم. اینکار باعث خواهد شد، پروژه refactoring آسان‌تری داشته باشد، همچنین باعث کاهش کد‌ها در سمت لایه business می‌گردد و یا اگر از DDD استفاده میکنید، در سرویس‌های خود به صورت چشم گیری کد‌های کمتر و واضح‌تری خواهید داشت. در مجموع راه حل‌های متنوعی برای پیاده سازی این روش ارائه شده است که یکی از آسان‌‌ترین روش‌های ممکن برای انجام اینکار استفاده‌ی درست از interface‌ها و همچنین بحث validation آن در سمت Generic repository میباشد.
فرض کنید در سمت مدل‌های خود User و Post را داشته باشیم و بخواهیم بصورت اتوماتیک رکورد‌های Post مربوط به هر User بارگذاری شود بطوریکه دیگر احتیاجی به نوشتن شرط‌های تکراری نباشد و در صورتیکه آن User از نوع Admin بود، همه‌ی Postها را بتواند ببیند. برای اینکار یک پروژه‌ی Console Application را در Visual studio به نام "Console1" ساخته و بصورت زیر عمل خواهیم کرد:

ابتدا لازم است Entity framework را توسط Nuget packages manager دانلود نمایید. سپس به پروژه‌ی خود یک فولدر جدید را به نام Models و درون آن ابتدا یک کلاس را به نام User اضافه کرده و بدین صورت خواهیم داشت :
using System;

namespace Console1.Models
{
    public enum UserType
    {
        Admin,
        Ordinary
    }
    public class User
    {
        public int Id { get; set; }

        public string Name { get; set; }

        public int Age { get; set; }

        public UserType Type { get; set; }

    }
}  

UserType نیز کاملا مشخص است؛ هر User نقش Admin یا Ordinary را می‌تواند داشته باشد.

نوبت به نوشتن اینترفیس IUser میرسد. در همین پوشه‌ای که قرار داریم، آن را پیاده سازی مینماییم:

namespace Console1.Models
{
    public interface IUser
    {
        int UserId { get; set; }

        User User { get; set; }
    }
}

هر entity که با User ارتباط دارد، باید اینترفیس فوق را پیاده سازی نماید. حال یک کلاس دیگر را به نام Post در همین پوشه درست کرده و بدین صورت پیاده سازی مینماییم.

using System.ComponentModel.DataAnnotations.Schema;

namespace Console1.Models
{
    public class Post : IUser
    {
        public int Id { get; set; }

        public string Context { get; set; }

        public int UserId { get; set; }

        [ForeignKey(nameof(UserId))]
        public User User { get; set; }

    }
}

واضح است که relation از نوع one to many برقرار است و هر User میتواند n تا Post داشته باشد.

خوب تا اینجا کافیست و میخواهیم مدل‌های خود را با استفاده از EF به Context معرفی کنیم. میتوانیم در همین پوشه کلاسی را به نام Context ساخته و بصورت زیر بنویسیم

using System.Data.Entity;

namespace Console1.Models
{
    public class Context : DbContext
    {
        public Context() : base("Context")
        {
        }

        public DbSet<User> Users { get; set; }

        public DbSet<Post> Posts { get; set; }
    }
}

در اینجا مشخص کرده‌ایم که دو Dbset از نوع User و Post را داریم. بدین معنا که EF دو table را برای ما تولید خواهد کرد. همچنین نام کلید رشته‌ی اتصالی به دیتابیس خود را نیز، Context معرفی کرده‌ایم.

خوب تا اینجا قسمت اول پروژه‌ی خود را تکمیل کرده‌ایم. الان میتوانیم با استفاده از Migration دیتابیس خود را ساخته و همچنین رکوردهایی را بدان اضافه کنیم. در Package Manager Console خود دستور زیر را وارد نمایید:

enable-migrations

به صورت خودکار پوشه‌ای به نام Migrations ساخته شده و درون آن Configuration.cs قرار می‌گیرد که آن را بدین صورت تغییر میدهیم:

namespace Console1.Migrations
{
    using Models;
    using System.Data.Entity.Migrations;

    internal sealed class Configuration : DbMigrationsConfiguration<Console1.Models.Context>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = true;
        }

        protected override void Seed(Console1.Models.Context context)
        {

            context.Users.AddOrUpdate(x => x.Id,
              new User { Id = 1, Name = "aaa", Age = 30, Type = UserType.Admin },
              new User { Id = 2, Name = "bbb", Age = 20, Type = UserType.Ordinary },
              new User { Id = 3, Name = "ccc", Age = 25, Type = UserType.Ordinary }
            );

            context.Posts.AddOrUpdate(x => x.Id,
                new Post { Context = "ccc 1", UserId = 3 },
                new Post { Context = "bbb 1", UserId = 2 },
                new Post { Context = "bbb 2", UserId = 2 },
                new Post { Context = "aaa 1", UserId = 1 },
                new Post { Context = "bbb 3", UserId = 2 },
                new Post { Context = "ccc 2", UserId = 3 },
                new Post { Context = "ccc 3", UserId = 3 }
            );

            context.SaveChanges();
        }
    }
}

در متد seed، رکورد‌های اولیه را به شکل فوق وارد کرده ایم (رکورد‌ها فقط به منظور تست میباشند*). در کنسول دستور Update-database را ارسال کرده، دیتابیس تولید خواهد شد.

قطعا مراحل بالا کاملا بدیهی بوده و نوشتن آنها بدین دلیل بوده که در Repository که الان میخواهیم شروع به نوشتنش کنیم به مدل‌های فوق نیاز داریم تا بصورت کاملا عملی با مراحل کار آشنا شویم.


حال میخواهیم به پیاده سازی بخش اصلی این مقاله یعنی repository که از Row Level Security پشتیبانی میکند بپردازیم. در ریشه‌ی پروژه‌ی خود پوشه‌ای را به نام Repository ساخته و درون آن کلاسی را به نام GenericRepository میسازیم. پروژه‌ی شما هم اکنون باید ساختاری شبیه به این را داشته باشد.

GenericRepository.cs را اینگونه پیاده سازی مینماییم

using Console1.Models;
using System;
using System.Linq;
using System.Linq.Dynamic;
using System.Linq.Expressions;

namespace Console1.Repository
{
    public interface IGenericRepository<T>
    {
        IQueryable<T> CustomizeGet(Expression<Func<T, bool>> predicate);
        void Add(T entity);
        IQueryable<T> GetAll();
    }

    public class GenericRepository<TEntity, DbContext> : IGenericRepository<TEntity>
        where TEntity : class, new() where DbContext : Models.Context, new()
    {

        private DbContext _entities = new DbContext();

        public IQueryable<TEntity> CustomizeGet(Expression<Func<TEntity, bool>> predicate)
        {
            IQueryable<TEntity> query = _entities.Set<TEntity>().Where(predicate);
            return query;
        }

        public void Add(TEntity entity)
        {
            int userId = Program.UserId; // یوزد آی دی بصورت فیک ساخته شده
                            // اگر از آیدنتیتی استفاده میکنید میتوان آی دی و هر چیز دیگری که کلیم شده را در اختیار گرفت

            if (typeof(IUser).IsAssignableFrom(typeof(TEntity)))
            {
                ((IUser)entity).UserId = userId;
            }

            _entities.Set<TEntity>().Add(entity);
        }

        public IQueryable<TEntity> GetAll()
        {
            IQueryable<TEntity> result = _entities.Set<TEntity>();

            int userId = Program.UserId; // یوزد آی دی بصورت فیک ساخته شده
                            // اگر از آیدنتیتی استفاده میکنید میتوان آی دی و هر چیز دیگری که کلیم شده را در اختیار گرفت

            if (typeof(IUser).IsAssignableFrom(typeof(TEntity)))
            {
                User me = _entities.Users.Single(c => c.Id == userId);
                if (me.Type == UserType.Admin)
                {
                    return result;
                }
                else if (me.Type == UserType.Ordinary)
                {
                    string query = $"{nameof(IUser.UserId).ToString()}={userId}";
                    
                    return result.Where(query);
                }
            }
            return result;
        }
        public void Commit()
        {
            _entities.SaveChanges();
        }
    }
}
توضیح کد‌های فوق

1) یک اینترفیس Generic را به نام IGenericRepository داریم که کلاس GenericRepository قرار است آن را پیاده سازی نماید.

2) این اینترفیس شامل متدهای CustomizeGet است که فقط یک predicate را گرفته و خیلی مربوط به این مقاله نیست (صرفا جهت اطلاع). اما متد Add و GetAll بصورت مستقیم قرار است هدف row level security را برای ما انجام دهند.

3) کلاس GenericRepository دو Type عمومی را به نام TEntity و DbContext گرفته و اینترفیس IGenericRepository را پیاده سازی مینماید. همچنین صریحا اعلام کرده‌ایم TEntity از نوع کلاس و DbContext از نوع Context ایی است که قبلا نوشته‌ایم.

4) پیاده سازی متد CustomizeGet را مشاهده مینمایید که کوئری مربوطه را ساخته و بر میگرداند.

5) پیاده سازی متد Add بدین صورت است که به عنوان پارامتر، TEntity را گرفته (مدلی که قرار است save شود). بعد مشاهد میکنید که من به صورت hard code به UserId مقدار داده‌ام. قطعا میدانید که برای این کار به فرض اینکه از Asp.net Identity استفاده میکنید، میتوانید Claim آن Id کاربر Authenticate شده را بازگردانید.

با استفاده از IsAssignableFrom مشخص کرده‌ایم که آیا TEntity یک Typeی از IUser را داشته است یا خیر؟ در صورت true بودن شرط، UserId را به TEntity اضافه کرده و بطور مثال در Service‌های خود نیازی به اضافه کردن متوالی این فیلد نخواهید داشت و در مرحله‌ی بعد نیز آن را به entity_ اضافه مینماییم.

مشاهده مینمایید که این متد به قدری انعطاف پذیری دارد که حتی مدل‌های مختلف به صورت کاملا یکپارچه میتوانند از آن استفاده نمایند. 

6) به جالبترین متد که GetAll میباشد میرسیم. ابتدا کوئری را از آن Entity ساخته و در مرحله‌ی بعد مشخص مینماییم که آیا TEntity یک Typeی از IUser میباشد یا خیر؟ در صورت برقرار بودن شرط، User مورد نظر را یافته در صورتیکه Typeی از نوع Admin داشت، همه‌ی مجموعه را برخواهیم گرداند (Admin میتواند همه‌ی پست‌ها را مشاهده نماید) و در صورتیکه از نوع Ordinary باشد، با استفاده از dynamic linq، کوئری مورد نظر را ساخته و شرط را ایجاد می‌کنیم که UserId برابر userId مورد نظر باشد. در این صورت بطور مثال همه‌ی پست‌هایی که فقط مربوط به user خودش میباشد، برگشت داده میشود.

نکته: برای دانلود dynamic linq کافیست از طریق nuget آن را جست و جو نمایید: System.Linq.Dynamic

و اگر هم از نوع IUser نبود، result را بر میگردانیم. بطور مثال فرض کنید مدلی داریم که قرار نیست security روی آن اعمال شود. پس کوئری ساخته شده قابلیت برگرداندن همه‌ی رکورد‌ها را دارا میباشد. 

7) متد Commit هم که پرواضح است عملیات save را اعمال میکند.


قبلا در قسمت Seed رکوردهایی را ساخته بودیم. حال میخواهیم کل این فرآیند را اجرا نماییم. Program.cs را از ریشه‌ی پروژه‌ی خود باز کرده و اینگونه تغییر میدهیم:

using System;
using Console1.Models;
using Console1.Repository;
using System.Collections.Generic;
using System.Linq;

namespace Console1
{
    public class Program
    {
        public static int UserId = 1; //fake userId
        static void Main()
        {
            GenericRepository<Post, Context> repo = new GenericRepository<Post, Context>();

            List<Post> posts = repo.GetAll().ToList();

            foreach (Post item in posts)
                Console.WriteLine(item.Context);

            Console.ReadKey();
        }
    }
}

همانطور که ملاحظه می‌کنید، UserId به صورت fake ساخته شده است. آن چیزی که هم اکنون در دیتابیس رفته، بدین صورت است که UserId = 1 برابر Admin و بقیه Ordinary میباشند. در متد Main برنامه، یک instance از GenericRepository را گرفته و بعد با استفاده از متد GetAll و لیست کردن آن، همه‌ی رکورد‌های مورد نظر را برگردانده و سپس چاپ مینماییم. در صورتی که UserId برابر 1 باشد، توقع داریم که همه‌ی رکورد‌ها بازگردانده شود:

حال کافیست مقدار userId را بطور مثال تغییر داده و برابر 2 بگذاریم. برنامه را اجرا کرده و مشاهد می‌کنیم که با تغییر یافتن userId، عملیات مورد نظر متفاوت می‌گردد و به صورت زیر خواهد شد:

میبینید که تنها با تغییر userId رفتار عوض شده و فقط Postهای مربوط به آن User خاص برگشت داده میشود.


از همین روش میتوان برای طراحی Repositoryهای بسیار پیچیده‌تر نیز استفاده کرد و مقدار زیادی از validationها را به طور مستقیم بدان واگذار نمود!

دانلود کد‌ها در Github

مطالب
بررسی ساختار جدول MigrationHistory در Entity Framework 6.x
EF اطلاعات تمام migrations اجرا شده‌ی بر روی بانک اطلاعاتی را در جدولی به نام MigrationHistory__ ذخیره می‌کند:


اگر به تصویر دقت کنید، در ستون Model آن، اطلاعات باینری ذخیره شده‌اند. شاید در وهله‌ی اول اینطور به نظر برسد که این ستون حاوی هش نقل و انتقالات صورت گرفته‌است؛ اما ... خیر. اطلاعات این ستون، GZip شده‌ی یک رشته‌ی XML ایی یا همان EDMX معادل مدل‌ها و نگاشت‌های برنامه است.
در کدهای ذیل، نمونه مثالی را از نحوه‌ی خواندن این اطلاعات، مشاهده می‌کنید:
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.IO;
using System.IO.Compression;
using System.Xml.Linq;
 
namespace EF_General
{
    public static class InsideMigrations
    {
        public static void PrintFirstMigrationModel()
        {
            const string connectionString = "Data Source=(local);Initial Catalog=TestDbIdentity;Integrated Security = true";
            const string sqlToExecute = "select top 1 model from __MigrationHistory";
 
            using (var connection = new SqlConnection(connectionString))
            {
                connection.Open();
 
                using (var command = new SqlCommand(sqlToExecute, connection))
                {
                    using (var reader = command.ExecuteReader())
                    {
                        if (!reader.HasRows)
                        {
                            throw new KeyNotFoundException("Nothing to display.");
                        }
 
                        while (reader.Read())
                        {
                            var model = (byte[]) reader["model"];
                            var decompressed = decompressMigrationModel(model);
                            Console.WriteLine(decompressed);
                        }
                    }
                }
            }
        }
 
        private static XDocument decompressMigrationModel(byte[] bytes)
        {
            using (var memoryStream = new MemoryStream(bytes))
            {
                using (var gzipStream = new GZipStream(memoryStream, CompressionMode.Decompress))
                {
                    return XDocument.Load(gzipStream);
                }
            }
        }
    }
}
در اینجا، اولین مدل ثبت شده‌ی در جدول migrations واکشی شده‌است. سپس به متد decompressMigrationModel برای رمزگشایی نهایی ارسال گردیده‌است.
بر اساس این اطلاعات، EF کاری به ساختار فعلی بانک اطلاعاتی شما ندارد. زمانیکه Add-Migration را اجرا می‌کنید، به جدول migrations مراجعه کرده، آخرین رکورد آن‌را یافته و سپس اطلاعات آن‌را از حالت فشرده خارج و XML نهایی آن‌را استخراج می‌کند. در ادامه اطلاعات این فایل XML را با معادل مدل‌های فعلی برنامه مقایسه می‌کند. اگر این دو یکی نبودند، اسکریپت اعمال تغییرات را تولید خواهد کرد.
مورد دیگری که در این جدول حائز اهمیت است، ستون ContextKey آن است: «رفع مشکل Migration با تغییر NameSpace در EF»  
مطالب
ایجاد زیر گریدهای چند سطحی در jqGrid
همانطور که در مطلب ایجاد زیرگریدها در jqGrid مشاهده کردید، هرچند این قابلیت برای نمایش لیست ساده‌ای از عناصر مفید است اما ... امکانات آنچنانی را به همراه ندارد. برای مثال صفحه بندی، جستجو، سفارشی سازی عناصر و غیره را به همراه ندارد. اگر علاقمند باشید که این امکانات را نیز اضافه کنید، می‌توان این زیرگرید را با یک گرید کامل jqGrid نیز جایگزین کرد. همچنین اگر نیاز بود، این گرید جدید چون یک jqGrid کامل است، باز هم می‌توان یک سطح دیگر را به آن افزود و الی آخر.



جایگزین کردن یک Subgrid با یک jqGrid کامل

خلاصه‌ی عملیات جایگزینی یک Subgrid را توسط یک jqGrid کامل، در ذیل مشاهده می‌کنید:
            $('#list').jqGrid({
                caption: "آزمایش دوازدهم",
                //..........مانند قبل
                subGrid: true,
                subGridRowExpanded: grid1RowExpanded
            });

        function grid1RowExpanded(subGridId, rowId) {
            var subgridTableId = subGridId + "_t";
            var pagerId = "p_" + subgridTableId;
            var container = 'g_' + subGridId;
            $("#" + subGridId).html('<div dir="rtl" id="' + container + '" style="width:100%; height: 100%">' +
                '<table id="' + subgridTableId + '" class="scroll"></table><div id="'
                + pagerId + '" class="scroll"></div>');

            var url = '@Url.Action("GetOrderDetails", "Home", routeValues: new { id = "js-id" })'
                      .replace("js-id", encodeURIComponent(rowId)); // تزریق اطلاعات سمت کاربر به خروجی سمت سرور

            $("#" + subgridTableId).jqGrid({
                caption: "ریز اقلام سفارش " + rowId,
                autoencode: true, //security - anti-XSS
                url: url,
                //..........مانند قبل
            });
        }
همانند نمایش subgridهای معمولی، ابتدا subGrid: true باید اضافه شود تا ستونی با ردیف‌های + دار، ظاهر شود. اینبار توسط روال رویدادگردان subGridRowExpanded، کنترل نمایش subgrid را در دست گرفته و آن‌را با یک jqGrid جایگزین می‌کنیم.
امضای متد grid1RowExpanded، شامل id یک div است که گرید جدید در آن قرار خواهد گرفت، به همراه Id ردیفی که اطلاعات زیرگرید آن نیاز است از سرور واکشی شود.
بر مبنای subGridId، مانند قبل، یک جدول و یک div را برای نمایش jgGrid و pager آن به صفحه به صورت پویا اضافه می‌کنیم.
سپس تعاریف jqGrid آن مانند قبل است و  نکته‌ی خاصی ندارد. بدیهی است گرید جدید نیز می‌تواند در صورت نیاز یک subgrid دیگر داشته باشد.
در اینجا تنها نکته‌ی مهم آن نحوه‌ی ارسال اطلاعات rowId به سرور است. اکشن متدی که قرار است اطلاعات زیر گرید را تامین کند، یک چنین امضایی دارد:
   public ActionResult GetOrderDetails(int id, JqGridRequest request)
بنابراین نیاز است که به نحوی rowId را به آن ارسال کرد. مشکل اینجا است که Url.Action یک کد سمت سرور است و rowId یک متغیر سمت کاربر. نمی‌توان این متغیر را در کدهای Razor مستقیما قرار داد. اما می‌توان یک محل جایگزینی را در کدهای سمت سرور پیش بینی کرد. مثلا js-id. زمانیکه این رشته در صفحه رندر می‌شود، به صورت معمول و به کمک متد replace جاوا اسکریپت، js-id آن‌را با rowId جایگزین می‌کنیم. به این ترتیب امکان تزریق اطلاعات سمت کاربر به خروجی سمت سرور Razor میسر می‌شود.


کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید:
jqGrid12.zip
مطالب
افزودن اکانت مدیریتی فراموش شده به SQL Server
فرض کنید
- تمام اکانت‌های مدیریتی توکار SQL Server را حذف کرده‌اید (یا برایتان حذف کرده‌اند).
- بجز کاربر SA، تمام کاربران را از نقش SYSADMIN حذف کرده‌اید؛ شامل تمام اکانت‌های ویندوزی و همچنین خود SQL Server.
- پسورد SA را هم فراموش کرده‌اید یا ندارید.

خوب، الان چکار می‌خواهید بکنید؟!
احتمالا نصب مجدد سرور را پیشنهاد دهید یا بانک اطلاعاتی Master را بازسازی کنید که در هر دو حالت تمام تنظیمات سرور را از دست خواهید داد. روش دیگری هم بدون از دست دادن تنظیمات سرور وجود دارد که در ادامه آن‌را بررسی خواهیم کرد.


افزودن یک اکانت مدیریتی جدید به SQL Server

اگر دسترسی کامل مدیریتی خود را به SQL Server از دست داده‌اید باید ابتدا به آن سرور لاگین کنید؛ با این فرض که کاربر وارد شده به سیستم، جزو local administrators group است.
 C:\>sqlcmd -S .
1> create login [MachineName\TestUser] from windows;
2> go
1> exec sp_addsrvrolemember 'MachineName\TestUser','sysadmin'
2> go
1> select is_srvrolemember('sysadmin', 'MachineName\TestUser')
2> go
-----------
1
(1 rows affected)
1>
سپس خلاصه مواردی را که ملاحظه می‌کنید، اجرای سه دستور است:
الف) اجرای sqlcmd با پارامتر S و مشخص سازی وهله‌ی مورد نظر
البته حالت کامل آن در صورتیکه از وهله‌ی پیش فرض استفاده نمی‌کنید SQLCMD –S Server_Name\Instance_Name است. S نیز در اینجا باید با حروف بزرگ نوشته شود.
ب) create login را بر روی یکی از اکانت‌های محلی سیستم اجرا کنید. مثلا MachineName\administrator یا هر اکانت موجود دیگری که لازم است. نام آن نیز باید حتما به شکل server_name\user_name باشد.
در حین استفاده از sqlcmd، هر فرمان زمانی اجرا می‌شود که در سطر پس از آن، یک go نوشته شده و enter شود.
ج) سپس توسط sp_addsrvrolemember به این اکانت اضافه شده، دسترسی sysadmin بدهید.

برای آزمایش آن فقط کافی است از متد is_srvrolemember برای کوئری گرفتن استفاده کنید و یا سعی کنید توسط اکانت اضافه شده، به SQL Server لاگین کنید. این اکانت اکنون در قسمت Security/logins قابل مشاهده است.

اگر نمی‌خواهید از اکانت‌های ویندوزی استفاده کنید، create login را به نحو ذیل مقدار دهی کنید:
 C:\>sqlcmd -S .
1> use master
2> go
Changed database context to 'master'.
1> create login test_user with password='123#123'
2> go
1> exec sp_addsrvrolemember 'test_user','sysadmin'
2> go
1>
سپس به این کاربر اضافه شده با کلمه‌ی عبور مشخص، توسط sp_addsrvrolemember دسترسی sysadmin بدهید.
مطالب
خواندن سریع اطلاعات فایل اکسل و ذخیره در بانک SQL
یکی از زمانبرترین عملیاتها در نرم افزار‌های اتوماسیون، خواندن اطلاعات از فایل‌های اکسل با حجم بالا است. در صورتی که این کار را می‌توان با استفاده از کلاس SqlBulkCopy  به سرعت انجام داد. در ادامه نحوه استفاده از این کلاس، همراه نمونه کدها آورده شده است.
توضیحات به صورت Comment است.
            try
            {
//انتخاب فایل اکسل
                OpenFileDialog ofd = new OpenFileDialog();
                ofd.Title = "انتخاب فایل اکسل حاوی اطلاعات";
                ofd.Filter = "فایل اکسل 2003 (*.xls)|*.xls|فایل اکسل 2007 به بعد(*.xlsx)|*.xlsx";
                if (ofd.ShowDialog() == DialogResult.OK)
                {
                    string excelConnectionString = "";
                    string SourceFilePath = ofd.FileName;
//ایجاد کانکشن استرینگ برا خواندن کل اطلاعات از فایل اکسل و ریختن آنها در یک دیتاتیبل به نام dt
                    if (System.IO.Path.GetExtension(ofd.FileName) == ".xlsx")
//تشخیص نوع فایل اکسل برای ایجاد کانکشن استرینگ برای نسخه‌های مختلف اکسل
                        excelConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + SourceFilePath + ";Extended Properties=Excel 12.0";
                    else if (System.IO.Path.GetExtension(ofd.FileName) == ".xls")
                        excelConnectionString = "Provider=Microsoft.Jet.Oledb.4.0;Data Source=" + SourceFilePath + ";Extended Properties=Excel 8.0";

                    DataTable dt = new DataTable("tblinfos");


                    using (System.Data.OleDb.OleDbConnection connection = new System.Data.OleDb.OleDbConnection(excelConnectionString))
                    {
                       
                        connection.Open();

                        System.Data.OleDb.OleDbDataAdapter da = new System.Data.OleDb.OleDbDataAdapter("SELECT * FROM [List$]", connection);//List نام شیت در فایل اکسل است

                        da.Fill(dt);
                        connection.Close();

                    }

                    using (System.Data.OleDb.OleDbConnection connection = new System.Data.OleDb.OleDbConnection(excelConnectionString))
                    {
                        this.Cursor = Cursors.WaitCursor;

                        connection.Open();
//ایجاد ارتباط با بانک اس کیو ال
                        string sqlConnectionString = @"Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\BankDPR.mdf;Max Pool Size=6000; Connection Timeout=50;Integrated Security=True;User Instance=True";
                        

                        Dataaccess db = new Dataaccess();
                        DataTable dtr = db.select("Select Top(1) * From tblinfos");//بدست آورن نام ستون‌های جدول مورد نظر برای تطبیق با ستونهای فایل اکسل
                        //*******************   Fast Copy
                        using (System.Data.SqlClient.SqlBulkCopy bulkCopy = new System.Data.SqlClient.SqlBulkCopy(sqlConnectionString, System.Data.SqlClient.SqlBulkCopyOptions.KeepIdentity))//تعریف یک شی از کلاس SqlBulkCopy 
                        {
                            for (int i = 1; i < dtr.Columns.Count; i++)
                            {
                                bulkCopy.ColumnMappings.Add(dt.Columns[i - 1].Caption, dtr.Columns[i].Caption);//با استفاده از خاصیت ColumnMappings نام ستونهای فایل اکسل با نام ستونهای جدول مورد نظر بانک sql تطبیق داده می‌شود
                            }

                            bulkCopy.DestinationTableName = "tblinfos";//مشخص نمودن نام جدول که قرار است اطلاعات درون ان کپی گردد
                            bulkCopy.WriteToServer(dt);//انجام عملیات کپی اطلاعات از دیتاتیبل با نام dt به بانک

                        }

                        this.Cursor = Cursors.Arrow;
                        MessageBox.Show("اطلاعات از فایل شما خوانده شد");

                    }
                }
            }
            catch (Exception ex)
            {
                this.Cursor = Cursors.Arrow;

                MessageBox.Show(ex.Message, "error");
            }

مطالب
Web.config File Transformation #1
یکی از مشکلات برنامه نویسان اختلاف بین فایل web.config تولید شده در سیستم خودشان و مقصد نهایی برنامه می‌باشد. در این مطلب به نحوه خودکار سازی تغییرات، برای توسعه بر روی مقصد نهایی برنامه می‌پردازیم. اکثر برنامه‌ها تنظیماتی در فایل web.config خود دارند که زمان عرضه برای مقصد نهایی می‌بایست تغییر کنند. پردازش خودکار این تغییرات کمک می‌کند تا از خطاهای ناشی از تغییرات دستی در زمان عرضه نهایی جلوگیری شود.


فایل‌های پیش فرض انتقالی
در پنجره Solution Explorer فایل web.config را بوسیله ایکون کنار آن باز کنید تا دو فایل پیش فرض web.Debug.config و web.Release.config که برای build configuration‌های برنامه ایجاد شده‌اند، مشاهده نمایید.

شما می‌توانید برای ایجاد build configuration دیگری، با راست کلیک کردن بر روی فایل web.config و انتخاب گزینه Add Config Transforms یک فایل دیگر را ایجاد نمایید. البته اگر این گزینه غیر فعال است، ابتدا می‌بایست یک build configuration جدید را ایجاد نمایید.

غیرفعال کردن حالت اشکال زدایی (debug)
در زمان عرضه نهایی برنامه دیگر لازم نیست تا امکان اشکال زدایی فعال باشد؛ به همین خاطر در فایل web.Release.config در تگ compilation مانند کد زیر از دستور RemoveAttributes استفاده می‌کنیم تا آن خاصیت را حذف نماید. 
<compilation xdt:Transform="RemoveAttributes(debug)" />

محدود کردن صفحات خطای برنامه فقط برای برنامه نویس
یکی دیگر از تنظیمات، عدم نمایش خطاهای برنامه به کاربر نهایی و انتقال آن به یک صفحه رخداد خطا می‌باشد:
<customErrors mode="Off" defaultRedirect="~/GenericErrorPage.aspx">
  <error statusCode="404" redirect="~/GenericErrorPage.aspx" />
</customErrors>
اما در زمان کد نویسی در محیط ویژوال استادیو می‌خواهیم mode را بر روی Off تنظیم نماییم تا خطا نمایش داده شود:
<customErrors mode="RemoteOnly" xdt:Transform="Replace" defaultRedirect="~/GenericErrorPage.aspx">
  <error statusCode="404" redirect="~/GenericErrorPage.aspx" />
</customErrors>
برای این کار از دستور Replace استفاده می‌کنیم تا تگ customErrors با مد RemoteOnly را جایگزین مد Off در زمان Release نماید.

تنظیم رشته اتصال پایگاه داده اصلی
مهمترین قسمت فایل web.config تگ connection string می‌باشد که باید به رشته اتصال پایگاه داده نهایی برنامه، تغییر یابد.
<connectionStrings>
      <add name="TestContext" 
        connectionString="Data Source=Server1;Password=****;User ID=sa; Initial Catalog=Test;Integrated Security=True" 
        xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
    </connectionStrings>
برای این کار از دستور SetAttributes مانند بالا استفاده می‌کنیم. اما چون ممکن است چندین connection string داشته باشیم، از دستور Match با مقدار name استفاده می‌کنیم، تا فقط رشته اتصالی که نام آن برابر رشته جاری می‌باشد را تغییر دهد که در اینجا TestContext را جستجو می‌نماید.

پیش نمایش connection string نهایی
برای مشاهده پیش نمایش نهایی web.config، بر روی فایل web.Release.config در پنجره Solution Explorer راست کلیک کنید و گزینه Preview Transform را انتخاب کنید.

هر دو فایل web.config اصلی و نهایی در کنار هم آورده می‌شود و اختلاف بین این دو را که برجسته‌تر شده است، می‌توانید مشاهده نمایید.

ادامه دارد...
مطالب
آشنایی با Contained Databases در SQL Server 2012
مقدمه:
بعضی وقت‌ها به هر دلیلی لازم است پایگاه داده برنامه هایمان را به سرور دیگری انتقال دهیم . برخلاف Oracle که انتقال پایگاه داده به سرور دیگر کار مشکل و تخصصی می‌باشد در SQL Server براحتی با یک Detach و Attach مجدد این انتقال انجام خواهد شد. اما اطلاعات Logins در پایگاه داده Master  سرور ذخیره شده است و با فایل پایگاه داده انتقال نمی‌یابد و به هیمن خاطر برخی مواقع پس از Attach پایگاه داده با پیغام The database is not accessible یا Cannot open user default database مواجع خواهیم شد که مشکل بخاطر همین نبود کاربران سرور قبلی و Owner متفاوت پایگاه داده می‌باشد که با استفاده از رویه ذخیره شده sp_change_users_login این مشکل قابل حل می‌باشد اما در SQL Server 2012 راحل بهتری فراهم شده است.

Contained Databases در Sql Server 2012
یکی از امکانات اضافه شده در SQL Server 2012  امکان Contained Databases  هست که برای حل همین مشکل و رفع کامل وابستی پایگاه داده با Instance نصب شده و خاصیت قابل حمل کامل database‌ها می‌باشد. در ادامه نحوه استفاده از این امکان را بررسی خواهیم کرد:
  1. فعال کردن خاصیت Contained Databases 

    قبل از استفاده از Contained Databases می بایست این امکان را فعال کرد. برای این کار می‌توانید از SQL Server Management Studio یا T-SQL commands استفاده نمایید. بر روی نام Instance راست کلیت کنید و گزینه Properties را انتخاب نمایید. از گزینه Advanced که در شکل زیر مشاهده می‌نمایید خاصیت Enable Contained Databases را بر روی True قرار دهید.

    یا می‌توایند از sp_configure این کار را انجام دهید.دستورات زیر این موضوع را نشان می‌دهد.
    sp_configure 'show advanced options',1
    GO
    RECONFIGURE WITH OVERRIDE
    GO
    sp_configure 'contained database authentication',1
    GO
    RECONFIGURE WITH OVERRIDE
    GO

  2. ایجاد یا تغییر یک پایگاه داده از نوع Contained Databases

    برای ایجاد یک پایگاه داده با این خاصیت یا تغییر پایگاه داده موجود کافیست مقدار گزینه Containment type را بر روی Partial قرار دهید. برای پایگاه داده موجود از پنجره Properties پایگاه داده صفحه Options را انتخاب کنید.


  3. ایجاد یک کاربر برای پایگاه داده Contained Databases

    برای تعریف یک کاربر در سطح پایگاه داده پوشه Security پایگاه داده خود را باز کنید بر روی پوشه Users راست کیلک و گزینه New User را انتخاب نمایید از گزینه User type که در شکل زیر نشان داده شده است SQL user with password را انتخاب نمایید و نام کاربر و رمز عبور و تکرار آن را وارد نمایید. کاربر ایجاد شده در سطح پایگاه داده می‌باشد و با انتقال به سرور دیگر نیر قابل دسترسی می‌باشد.

  4.  اتصال به پایگاه داده Contained Databases

    برای اتصال به پایگاه داده کافیست در حالت SQL Server Authentication نام کاربری و رمز عبور جدید را وارد و گزینه Options  را انتخاب و از برگه Additional Connection Parameters نام پایگاه داده مورد نظر را مانند شکل زیر وارد نمایید پس از ورود تنها پایگاه داده خود را مشاهده می‌نمایید. یکی از کاربرهای این قابلیت برای مدیران سرور پایگاه داده می‌باشد که بدون استفاده از مجوز sysadmin  به کاربران اجازه دسترسی را می‌دهد.



مطالب
نحوه‌ی مشاهده‌ی خروجی SQL تولید شده توسط WCF RIA Services

این روزها با وجود ORMs ، کوئری SQL‌ نوشتن شبیه به دورانی شده که با وجود زبان‌های سطح بالا، عده‌ای علاقمند هستند با استفاده از زبان اسمبلی برنامه نویسی کنند! WCF RIA Services به صورت پیش فرض از entity framework استفاده می‌کند (هر چند می‌توان از سایر ORMs هم استفاده کرد)، بنابراین عنوان صحیح‌تر بحث این خواهد بود: چگونه خروجی SQL تولید شده توسط Entity framework را بررسی کنیم؟

الف) استفاده از SQL Server profiler
اولین برنامه‌ای که از سال‌ها قبل، حتی پیش از ظهور ORMs وجود داشته، برنامه‌ی SQL server profiler است، که عموما در مسیر ذیل قابل دستیابی است:
Start Menu->Programs->Microsoft SQL Server 2008->Performance Tools->SQL Server profiler



نکته مهم:
حین کار با SQL Server profiler ، ممکن است انبوهی از کوئری‌های دیگر مثلا مرتبط با SQL Server agent یا reporting services و غیره نیز لاگ شوند. اما الان ما تنها به کوئری‌های برنامه‌ی خود نیاز داریم. برای این منظور به کانکشن استرینگ خود، گزینه‌ی Application Name=My Application Name را نیز اضافه کنید:

<connectionStrings>
<add name="dmEntities" connectionString="metadata=res://*/Models.dmDataModel.csdl|res://*/Models.dmDataModel.ssdl|res://*/Models.dmDataModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=(local);Initial Catalog=dm;Integrated Security=True;Application Name=My Application Name;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />
</connectionStrings>

اکنون اگر برنامه را با پروفایلر مورد بررسی قرار دهید خروجی به صورت زیر خواهد بود:



برای فیلتر کردن Application Name مورد نظر، در ابتدای کار که یک سشن جدید را آغاز می‌کنید به برگه‌ی events selection مراجعه کرده و بر روی دکمه‌ی column filter کلیک کنید. گزینه‌ی application name را در صفحه‌ی باز شده انتخاب نموده و در قسمت Like آن مطابق تصویر زیر ، نام برنامه‌ی خود را وارد نمائید:




ب) استفاده از IntelliTrace در VS.NET 2010
برنامه را در حالت دیباگ در VS.NET 2010 اجرا کنید. در هر لحظه‌ای می‌توان روی گزینه‌ی Break all کلیک کرد و خروجی SQL تولید شده را نیز علاوه بر اطلاعات دیگر مشاهده نمود:




ج) استفاده از برنامه‌ی حرفه‌ای entity framework profiler
این برنامه از هر دو مورد قبل کاملتر بوده و اساسا برای لاگ کردن کوئری‌ها، مدت زمان اجرا، گزارشگیری از وضعیت برنامه، کدامیک از کوئری‌ها سنگین‌تر هستند، حتی از طریق کدام متد فراخوانی شده‌اند، ارائه‌ی گزارشات و راهنمایی‌هایی در مورد چگونگی بهبود کارآیی برنامه‌ی تهیه شده و امثال آن کاربرد دارد.



استفاده از آن هم بسیار ساده است. ابتدا ارجاعی را به اسمبلی HibernatingRhinos.Profiler.Appender.v4.0 به پروژه‌ی ASP.NET خود اضافه کنید (همان پروژه‌ی هوست مربوط به WCF RIA Service ما). سپس به فایل Global.asax.cs برنامه مراجعه کرده و یک سطر ذیل را اضافه کنید:

protected void Application_Start(object sender, EventArgs e)
{
HibernatingRhinos.Profiler.Appender.EntityFramework.EntityFrameworkProfiler.Initialize();
}

از این پس تنها کافی است برنامه‌ی پروفایلر در حال اجرا بوده و برنامه شما نیز اجرا شود. کلیه‌ی تبادلات با دیتابیس لاگ خواهند شد.

مطالب
سه مطلب کوتاه

مشکل فایرفاکس با سایت‌های msdn و codeplex
هر از چند گاهی در بلاگ‌های msdn و یا سایت codeplex با خطای زیر از طرف سایت مواجه می‌شوم:

Bad Request - Request Too Long
HTTP Error 400. The size of the request headers is too long.

اگر با این مشکل مواجه شدید، تمامی کوکی‌های مربوط به سایت‌های مذکور را یافته و حذف کنید.
به نظر باگی در فایرفاکس در این زمینه سبب می‌شود که کوکی‌های تمام زیر سایت‌های فوق با هم ترکیب شده و رشته‌ا‌ی بسیار طولانی بجای کوکی اصلی آن زیر سایت به هاست ارسال شود.
که البته عکس العمل سایت‌های مایکروسافت از دیدگاه امنیتی هم جالب توجه است (برای برنامه نویس‌های وب).


IE8 و ارائه‌ی fakepath بجای آدرس فایل
کنترل استاندارد آپلود فایل در مرورگرهای جدید، دیگر آدرس محلی فایل را حتی در اختیار اسکریپت‌های سمت کاربر نیز قرار نمی‌دهند. فایرفاکس مدت زیادی است که این مورد را پیاده سازی کرده. اما IE بجای اینکه یک رشته‌ی خالی را بازگشت دهد مسیر c:\fakepath را ارائه خواهد داد (fakepath جزو استاندارد html 5 است). اگر احیانا با این مورد برخورد داشتید، با استفاده از تنظیم زیر می‌توان مانند سابق مسیر کامل را نیز دریافت کرد:

Internet Explorer -> Tools -> Internet Option -> Security -> Custom ->
find the "Include local directory path when uploading files to a server"
-> click on "Enable"

اهمیت این مورد هم برای من این است که IE، یعنی همان مرورگر کاری در اکثر شرکت‌ها (و این مورد فوق را به سادگی از طریق گروپ پالیسی می‌توان به تمام کامپیوترها اعمال کرد).

علت تایم آوت و باز نشدن یک سری از سایت‌ها در ایران
مدت زیادی این سؤال برای من وجود داشت که وجه مشترک سایت‌هایی مانند dotnetkicks.com ، summerofnhibernate.com ، lessthandot.com و امثال آن چیست که از این طرف باز نمی‌شوند؟
اگر به آدرس‌های فوق که به سایت domaintools.com ختم می‌شوند، مراجعه کنید و سپس برگه‌ی Server Stats آن‌ها را ملاحظه نمائید، همگی توسط Godaddy.com Inc هاست می‌شوند. این شرکت غیرمحترم، IP های ایرانی را بسته است (مطلب جدیدی هم نیست).