مطالب
یکی کردن اسمبلی‌های ارجاعی یک برنامه WPF با فایل خروجی آن
ممکن است برای شما هم پیش آمده باشد که بخواهید پس از پابلیش برنامه‌ای که نوشته‌اید، تمامی فایل‌های اسمبلی استفاده شده در برنامه را نیز با فایل خروجی آن ادغام کنید و به اصلاح تنها یک فایل، برای اجرا داشته باشید. مایکروسافت ابزاری را به نام ILMerge، برای اینکار معرفی کرده است که به وسیله آن، امکان ادغام اسمبلی‌ها با فایل اصلی برنامه وجود دارد؛ بجز اسمبلی‌های مربوط به WPF، به خاطر داشتن فایل‌های XAML.
برای حل این مسئله می‌توان از دو راه استفاده کرد:
  • اضافه کردن اسمبلی‌ها به صورت دستی به پروژه و تنظیم Build Action آن‌ها به Embedded Resource
  • تنظیم فایل csproj پروژه برای Embed کردن خودکار رفرنس‌های پروژه در زمان Build


روش اول

بعد از این که ارجاع اسمبلی مورد نظر را به پروژه اضافه کردید، نیاز است مقدار Copy Local آن‌ها را نیز در پنجره Properties به False تغییر دهید و سپس با استفاده از گزینه Add -> Existing Item فایل اسمبلی مورد نظر را به پروژه اضافه کرده و مقدار Build Action را در پنجره Properties به Embedded Resource تغییر دهید.
نکته: در صورتی که فایل اسمبلی به صورت unmanaged / native داشتید و امکان افزودن ارجاعی به آن وجود نداشت، تنها کافیست آن را به صورت Embedded Resource اضافه کنید.
تا به اینجا کار ادغام اسمبلی‌ها با فایل خروجی برنامه با موفقیت انجام شد و به علت یکسان بودن کد مربوط به بارگذاری اسمبلی‌ها، بعد از روش دوم، توضیح داده خواهد شد.


روش دوم

در این روش باید فایل csproj و یا vbproj برنامه را در یک ادیتور باز کرده ( یا با استفاده از گزینه Unload Project و انتخاب گزینه Edit projectName.csproj ) و در قسمت انتهای فایل، قبل از تگ Project، این کد را اضافه می‌کنیم:
<Target Name="EmbedReferencedAssemblies" AfterTargets="ResolveAssemblyReferences">
  <ItemGroup>
    <AssembliesToEmbed Include="@(ReferenceCopyLocalPaths)" />
    <EmbeddedResource Include="@(AssembliesToEmbed)" Condition="'%(AssembliesToEmbed.Extension)' == '.dll'">
      <LogicalName>%(AssembliesToEmbed.DestinationSubDirectory)%(AssembliesToEmbed.Filename)%(AssembliesToEmbed.Extension)</LogicalName>
    </EmbeddedResource>
  </ItemGroup>
  <Message Importance="high" Text="Embedding: @(AssembliesToEmbed->'%(DestinationSubDirectory)%(Filename)%(Extension)', ', ')" />
</Target>
<Target Name="DeleteAllReferenceCopyLocalPaths" AfterTargets="Build">
  <Delete Files="@(ReferenceCopyLocalPaths->'$(OutDir)%(DestinationSubDirectory)%(Filename)%(Extension)')" />
</Target>
بعد از اضافه کردن این کد به فایل پروژه و بارگذاری مجدد پروژه، با اجرای برنامه یا Build کردن آن، در پوشه bin (پوشه خروجی برنامه) مشاهده می‌کنید که فایل‌های اسمبلی ارجاعی برنامه در این پوشه وجود ندارند و حجم فایل خروجی افزایش یافته است.

همانطور که در تصویر بالا نیز مشاهده می‌کنید، اسمبلی‌های ارجاعی برنامه TestApp به صورت Resource به آن اضافه شده‌اند.


نحوه بارگذاری اسمبلی‌های Embed شده

در پروژه‌های WPF، در OnStartup event کلاس App و در پروژه‌های WinForm در متد Main کلاس Program، قطعه کد زیر را وارد می‌کنیم:

private void App_OnStartup( object sender, StartupEventArgs e )
{
    AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly;
    var assembly = Assembly.GetExecutingAssembly();
    foreach (var name in assembly.GetManifestResourceNames())
    {
        if ( name.ToLower()
                 .EndsWith( ".resources" ) ||
             !name.ToLower()
                  .EndsWith( ".dll" ) )
            continue;
        EmbeddedAssembly.Load( name,
                               name );
    }
}

static Assembly OnResolveAssembly( object sender, ResolveEventArgs args )
{
    var fields = args.Name.Split( ',' );
    var name = fields[0];
    var culture = fields[2];
    if ( name.EndsWith( ".resources" ) &&
         !culture.EndsWith( "neutral" ) )
        return null;

    return EmbeddedAssembly.Get( args.Name );
}

با استفاده از رویداد AssemblyResolve می توان اسمبلی Embed شده را در زمانیکه نیاز به آن است، بارگذاری کرد. کد مربوط به کلاس EmbeddedAssembly نیز به این صورت می‌باشد:

using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Security.Cryptography;

public static class EmbeddedAssembly
{
    static Dictionary< string, Assembly > _dic;

    public static void Load( string embeddedResource,
                                string fileName )
    {
        if ( _dic == null )
            _dic = new Dictionary< string, Assembly >();

        byte[] ba;
        Assembly asm;
        var curAsm = Assembly.GetExecutingAssembly();

        using ( var stm = curAsm.GetManifestResourceStream( embeddedResource ) )
        {
            if ( stm == null )
                return;

            ba = new byte[(int)stm.Length];
            stm.Read( ba,
                      0,
                      (int)stm.Length );
            try
            {
                asm = Assembly.Load( ba );

                _dic.Add( asm.GetName().Name,
                            asm );
                return;
            }
            catch
            {
            }
        }

        bool fileOk;
        string tempFile;

        using ( var sha1 = new SHA1CryptoServiceProvider() )
        {
            var fileHash = BitConverter.ToString( sha1.ComputeHash( ba ) )
                                        .Replace( "-",
                                                    string.Empty );

            tempFile = Path.GetTempPath() + fileName;

            if ( File.Exists( tempFile ) )
            {
                var bb = File.ReadAllBytes( tempFile );
                var fileHash2 = BitConverter.ToString( sha1.ComputeHash( bb ) )
                                            .Replace( "-",
                                                        string.Empty );

                fileOk = fileHash == fileHash2;
            }
            else
            {
                fileOk = false;
            }
        }

        if ( !fileOk )
        {
            File.WriteAllBytes( tempFile,
                                ba );
        }

        asm = Assembly.LoadFile( tempFile );

        _dic.Add( asm.GetName().Name,
                    asm );
    }

    public static Assembly Get( string assemblyFullName )
    {
        if ( _dic == null ||
                _dic.Count == 0 )
            return null;

        var name = new AssemblyName( assemblyFullName ).Name;
        return _dic.ContainsKey( name )
            ? _dic[name]
            : null;
    }
}

با استفاده از متد Load کلاس بالا، کل اسمبلی‌هایی که بارگذاری شده‌اند در یک دیکشنری استاتیک نگهداری می‌شوند. ابتدا اسمبلی‌ها را با استفاده از []byte بارگذاری می‌کنیم و در صورتیکه بارگذاری اسمبلی با خطایی مواجه شود، بارگذاری را با استفاده از فایل temp انجام می‌دهیم (که معمولا برای فایل‌های unmanaged این مورد اتفاق می‌افتد).

با استفاده از متد Get که در زمان نیاز به یک اسمبلی توسط AssemblyResolve فراخوانی می‌شود، اسمبلی مربوطه از دیکشنری پیدا شده و برگشت داده می‌شود.


نکته ها

  • در صورتیکه بخواهید فایلی را از Embed کردن خودکار (روش دوم) استثناء کنید، باید از Condition استفاده کنید:
  <Target Name="EmbedReferencedAssemblies" AfterTargets="ResolveAssemblyReferences">
    <ItemGroup>
      <AssembliesToEmbed Include="@(ReferenceCopyLocalPaths)" />
      <EmbeddedResource Include="@(AssembliesToEmbed)" Condition="$([System.Text.RegularExpressions.Regex]::IsMatch('%(AssembliesToEmbed.Filename)', '^((?!Microsoft).)*$')) And '%(AssembliesToEmbed.Extension)' == '.dll'">
        <LogicalName>%(AssembliesToEmbed.DestinationSubDirectory)%(AssembliesToEmbed.Filename)%(AssembliesToEmbed.Extension)</LogicalName>
      </EmbeddedResource>
    </ItemGroup>
    <Message Importance="high" Text="Embedding: @(AssembliesToEmbed->'%(DestinationSubDirectory)%(Filename)%(Extension)', ', ')" />
  </Target>
  <Target Name="DeleteAllReferenceCopyLocalPaths" AfterTargets="Build">
    <Delete Files="@(ReferenceCopyLocalPaths->'$(OutDir)%(DestinationSubDirectory)%(Filename)%(Extension)')" Condition="$([System.Text.RegularExpressions.Regex]::IsMatch('%(Filename)', '^((?!Microsoft).)*$')) Or '%(Extension)' == '.xml'" />
  </Target>

برای نمونه در اینجا با استفاده از Regex، تمامی فایل‌هایی که شروع نام آنها با Microsoft است، استثناء شده‌اند. فقط توجه داشته باشید در صورتیکه شرطی را برای Embed کردن تعریف می‌کنید، حتما در هر دو قسمت، شرط را وارد کنید.
  • در صورتیکه بعد از اجرای برنامه و یا اجرای به صورت دیباگ با خطای Stackoverflow مواجه شدید که به خاطر ارجاعات زیاد Resource‌های برنامه پیش می‌آید، کد زیر را به فایل AssemblyInfo، در پوشه Properties اضافه کنید:
[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.MainAssembly)]


  • در صورتیکه پروژه شما از نوع Office Add-Ins باشد، باید در کد مربوط به AssemblyResolve را در فایل ThisAddIn.Designer.cs (در صورت عدم تغییر نام) به متد Initialize اضافه کنید و دستور بارگذاری را در متد ThisAddIn_Startup اضافه کنید. نکته خیلی مهم:  در فایل csproj حتما در قسمت Condition باید اسمبلی‌هایی را که با نام Microsoft شروع می‌شوند، از Embed شدن استثناء کنید و در قسمت DeleteAllReferenceCopyLocalPaths مقدار "AfterTargets="VisualStudioForApplicationsBuild را قرار دهید (تا امکان Build پروژه برای شما باشد) و همچنین پسوند vsto را نیز نباید حذف کنید.

مطالب
احراز هویت مبتنی بر فرم در شیرپوینت
از دغدغه‌های همیشگی در راه اندازی پرتال‌های مبتنی بر شیرپوینت سیستم احراز هویت آن است. این سیستم بصورت پیش فرض بر مبنای Windows Authentication است و ناگفته پیداست این نوع احراز هویت تنها در شبکه‌های محلی کاربرد دارد آنهم در صورتی که همه کاربران و سطوح دسترسی، بدرستی در AD تعریف شده باشد و نیز
یک سری مشکلات دیگر که بیشتر به توسعه شیرپوینت در شرکت و انتقال آن و انطباق آن با محیط پروژه برمیگردد.
به عبارت دیگر شما به عنوان یک توسعه دهنده ویا نَصاب(!) شیرپوینت خیلی نباید درگیر سیستم احراز هویت پیش فرض مشتری بشوید. برای اینکار بهترین گزینه استفاده از احراز هویت بر مبنای فرم (Form Based Authentication - FBA) است که برای ما برنامه نویسان Asp.net بسیار آشناست؛ سیستم احراز هویتی خوش دست و فراگیر با قاعده‌های مشخص.

متاسفانه اکثر راهکارهایی که در وب پیرامون راه اندازی FBA در شیرپوینت معرفی شده‌اند دارای اشکالات ریز و درشتی هستند و یا اینکه یک یا چند گام از فرایند را توضیح نداده‌اند و معمولا در پایان یکجای کار لنگ میزند و FBA بخوبی عملیاتی نمیشود.
بر همین اساس بر آن شدم تا با بررسی چندتا از این مقالات موجود و نیز تجربه عملی خودم این راهکارها را ترکیب کنم که نتیجه اش فرایند شش مرحله ای زیر شده است. 
 برای راه اندازی FBA بر روی SharePoint 2010 باید مراحل زیر را به ترتیب انجام داد.
1. ساخت بانک اطلاعاتی FBA بر روی MSSQL
بانک اطلاعاتی FBA ساختار مشخصی از جداول و SP‌ها دارد که تا حد امکان بهتر است در ساختار پیش فرض آن تغییری ایجاد نکنیم. برای ایجاد این بانک کافی است به محل نصب دات نت فریم 2.0 که بصورت پیش فرض در مسیر"C:\Windows\Microsoft.NET\Framework64\v2.0.50727 " قرار دارد  بروید و روی فایل "aspnet_regsql.exe "  کلیک کنید و مراحل نصب را تا آخر پیش بروید.

در ادامه MSSQL را باز کنید و مطئمن شوید که بانک FBA به درستی ایجاد شده باشد.

2.وارد IIS شده و در بخش روت سرور ،توجه شود که حتما این تغییرات در روت سرور اعمال شود تا همه سایت‌ها از آن ارث بری کنند و تنظیمات شما یکسان در همه Web Application‌ها اعمال شود.
این مرحله  Connection String و Role provider و Membership provider مورد نظرتان را اضافه کنید. 

موقع اضافه کردن Provider‌‌ها باید توجه داشت که Application Name برابر "/" قرار داده شود.

 3.به بخش مدیریت شیرپوینت رفته و یک WebApplication جدید ایجاد کنید.

توجه داشت که در بخش Authentication بایدگزینه    Claims Authentication را انتخاب کنید. 

و نیز برای تنظیمات مربوط به FBA باید نام Provider هایی را که در مرحله قبل ایجاده کرده بودید را در این بخش قرار دهید.
اگر پرتال شما بازدید کننده‌های ناشناس(بازدید کنندگانی که عضو نیستند و در سیستم FBA نام کاربری ندارند) را نیز پشتیبانی میکند باید گزینه اول(Allow anonymous) را Yes کنید.
اگر تمایلی ندارید که دیگر احراز هویت مبتنی بر ویندوز فعال باشد تیک Enable Windows Authentication را بردارید.

 

4.حال دوباره سراغ IIS میرویم و روی وب جدیدی که ایجاد کرده ایم کلیک میکنیم و سپس روی آیکون Net Users  کلیک میکنیم

 اگر با پیغامی مبنی بر تعیین Provider پیش فرض مواجه شدیم مقادیر پیش فرض Provider‌ها را برابر با نام Provider هایی که خودمان تعریف کرده ایم قرار میدهیم. 

در ادامه چند کاربر و رول هم به عنوان کاربران اولیه و مدیران پرتال ایجاد میکنیم .

 

5.حال دوباره به بخش مدیریت برمیگردیم و یک Site Collection جدید روی Web Application مورد نظر ایجاد میکنیم.

در اینجا بهتر است مدیر اول را از کاربران ویندوزی انتخاب کرد و مدیر دوم را از بخش کاربران FBA

نکته بی ربط:اگر تمپلتی از قبل برای سایتتان دارید در بخش انتخاب نوع سایت بعد از انتخاب زبان باید به تب سوم(Custom) بروید و تنها گزینه موجود را انتخاب کنید.با این کار در مراحل بعد تمپلت مورد نظرتان را در سایت آپلود میکنید و آن را بر سایت جاری اعمال میکنید.
 در این مرحله بعد از ایجاد موفقیت آمیز Site collection دوباره به IIS سری بزنید و پس از انتخاب Web Application مورد نظر بروی Authentication کلیک کنید و مطمئن شوید که Form Authentication مقدارش Enable میباشد. در این بخش اگر هر دو حالت Form Base Authentication و Windows Authentication فعال باشد IIS در گوشه سمت راست به شما خطایی نمایش میدهد مبنی بر اینکه شما نباید هر دو حالت را همزمان فعال کنید. البته خیلی این تذکر را جدی نگیرید و بکارتان ادامه دهید و در نهایت بعد از اینکه مراحل را کامل انجام دادید و از اجرای کامل FBA اطمینان حاصل نمودید،میتوانید برگردید و حالت Windows Authentication را غیر فعال کنید.
 6.تنظیمات STS:
علاوه بر تنظیمات مربوط به بخش Web Application باید تنظیمات FBA را روی Application سرویس‌ها نیز انجام داد تا سرویس‌های WCF نیز پشتیبانی از FBA را بپذیرند. برای تنظیمات این بخش روی Security Token Service Application که زیر مجموعه SharePoint Web Services قرار دارد کلیک کنید.

 
در ادامه تنها کافی است Connection string را جهت اتصال به بانکی که در ابتدا ساختیم ایجاد کرده و Provider‌ها را نیز مطابق قبل اضافه کنیم. فقط توجه شود Connection string و Provider‌ها همنام قبلی‌ها نباشند ولی Application Name همچنان برابر با "/" مقدار دهی شود.
هیچ تغییر دیگری در این Application ایجاد نشود.مثلا Authentication به هیچ وجه تغییر نکند و در حالت ویندوزی باقی بماند.
کار تقریبا به پایان رسیده است،میتوانید در پرتال لاگین کنید!
آنچنانکه که در تصویر می‌بینید هر دو حالت ویندوزی و FBA برای احراز هویت فعال می‌باشد.

 پی نوشت:
1.همانطور که احتمالا متوجه شده اید این آموزش با راهکارهای حاضر یک سری تفاوت‌ها داشت که عمده‌ترین آن عدم تغییر در بخش احراز هویت مدیریت شیرپوینت بود. علت این امر نیز به این خاطر است که اساسا هر کاربری به این بخش دسترسی ندارد و تنها مدیر سیستم است که باید به این بخش دسترسی داشته باشد، بر همین اساس ترجیح میدهم احراز هویت آن به همان شکل اولیه(Windows Authentication ) باقی بماند.
2.در این نوشته من از شرح تنظیمات و نکات ریز و بدیهی خوداری کردم با این پیش فرض که خواننده مطلب، بر اصول پایه شیرپوینت و Asp.net آگاهی دارد. در غیر این صورت بهتر است از لینک هایی مرجع زیر کمک بگیرید.
نظرات مطالب
PowerShell 7.x - قسمت پنجم - اسکریپت بلاک و توابع
بلاک clean نیز از نسخه 7.3 به PowerShell اضافه شده است. از این بلاک میتوانیم برای آزادسازی منابع به‌کار رفته استفاده کنیم. این بلاک خیلی شبیه به finally عمل میکند. مزیت آن نیز reliable بودن آن است. در حالت استفاده از finally، متوقف شدن Pipeline خیلی reliable نیست و بهتر است از بلاک clean بجای آن استفاده شود:
using namespace System.Net.NetworkInformation

## Pinging a remote system
function Get-PingReply {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory, ValueFromPipeline)]
        [Alias('IPAddress', 'Destination')]
        [string] $Target
    )
    begin {
        $Ping = [Ping]::new()

        # Timeout is in ms
        $Timeout = 2500
        [byte[]] $Buffer = 1..32

        # 128 TTL and avoid fragmentation
        $PingOptions = [PingOptions]::new(128, $true)
    }
    process {
        $Ping.Send($Target, $Timeout, $Buffer, $PingOptions)
    }
    clean {
        if ($Ping) { $Ping.Dispose() }
    }
}

'1.2.3.4', 'www.google.com', '8.8.8.8' | Get-PingReply
نظرات مطالب
پیاده سازی پروژه نقاشی (Paint) به صورت شی گرا 2#
با سلام

از مطلب مفیدی که تهیه کردید ممنون.
می‌شود از طریق خاصیت Brush که فعلا فقط خواندنی هست، طرح‌های مختلفی برای پس زمینه اشیاع ایجاد کرد. مانند Paint.net و یا MS Paint.

اگر به صورت زیر تعریف کنیم فکر می‌کنم کمی کامل‌تر باشه!

        private Brush _backgroundBrush;

        /// <summary>
        /// Gets or sets the brush.
        /// </summary>
        /// <value>
        /// The brush.
        /// </value>
        public Brush BackgroundBrush
        {
            get
            {
                return _backgroundBrush;
            }
            private set
            {
                _backgroundBrush = (value != null) ? value : new SolidBrush(BackgroundColor);
            }
        }
        //-------------------------------------[Methode for set brush]--------------------------------------
        public virtual void SetBackgroundBrushAsHatch(HatchStyle hatchStyle)
        {
            HatchBrush brush = new HatchBrush(hatchStyle, BackgroundColor);
            BackgroundBrush = brush;
        }

        public virtual void SetBackgroundBrushAsSolid()
        {
            SolidBrush brush = new SolidBrush(BackgroundColor);
            BackgroundBrush = brush;
        }

        public virtual void SetBackgroundBrushAsLinearGradient()
        {
            LinearGradientBrush brush = new LinearGradientBrush(StartPoint, EndPoint, ForeColor, BackgroundColor);
            BackgroundBrush = brush;
        }

که اگر بخواهیم میتونیم باز بیشتر Customize بکنیمشون.
نظرات مطالب
ASP.NET MVC #12
سلام آقای نصیری
با تشکر از توضیحاتتون
من کد زیر رو که خودتون واسه شمسی کردن تاریخ گذاشته بودین، به نام datetime.cshtml و صورت PartialView داخل پوشه DisplayTemplates قرار دادم. اما همچنان DateTime‌ها رو به فرمت میلادی نمایش میده. میشه بگین اشکال کارم کجاست ؟
@using System.Globalization
@model Nullable<DateTime>
           
@helper ShamsiDateTime(DateTime info, string separator = "/", bool includeHourMinute = true)
{
    int ym = info.Year;
    int mm = info.Month;
    int dm = info.Day;
    var sss = new PersianCalendar();
    int ys = sss.GetYear(new DateTime(ym, mm, dm, new GregorianCalendar()));
    int ms = sss.GetMonth(new DateTime(ym, mm, dm, new GregorianCalendar()));
    int ds = sss.GetDayOfMonth(new DateTime(ym, mm, dm, new GregorianCalendar()));    
    if (includeHourMinute)
    {
        @(ys + separator + ms.ToString("00") + separator + ds.ToString("00") + " " + info.Hour + ":" + info.Minute)
    }
    else
    {
        @(ys + separator + ms.ToString("00") + separator + ds.ToString("00"))
    }
}

@if (@Model.HasValue)
{
  @ShamsiDateTime(@Model.Value , separator: "/", includeHourMinute: false)
}

نظرات مطالب
نحوه‌ی مشاهده‌ی خروجی SQL تولید شده توسط WCF RIA Services
-امنیت: دلیل امنیت فقط در تشخیض SQL-Injection نیست! اگر با ابزارهایی مثل acunetix سایت رو تست کنید، میبینید که میشه یک threshold در حد MS درآورد که میشه تشخیص اینجکشن رو داد. بله EF و SP این اشتراک رو دارن که نمیشه اینجکت کرد ولی میشه Vulnerability رو تشخیص داد.
-شخصا به خاطر مشکلات Deployment سعی میکنم BL بیشتر در SP باشه.
-در مورد تغییرات هم عرض کنم، ابزارهایی مثل SQL-ToolBelt مشکل رو حل کردن.
- اینکه برنامه به tightly couple نشه خوبه.
- Round Trip زیاده! به طور مثال فرض کنید یک مقدار تولیدی برای یک فیلد که کلید اصلی است(GUID یا Identity) البته فنون شرقی دارن ولی راه حل استانداردی نیستن!
- تمامی مباحث Loading درست ولی باید یک Trade Off بین بزرگی DB ، سرعت نگاشت، قابل اطمینان بودن!(EF برخی قابلیت ها رو نداره اینجا رو نگاه کنیدhttp://blogs.msdn.com/b/alexj/archive/2009/03/26/index-of-tips.aspx البته انتظار که ندارید سازنده ش مستقیم بگه نمیشه!)

بحث Change Tracking واقعا عالیه ولی به طور کلی، در یک برنامه Enterprise نمیشه از EF استفاده کرد(به همراه OData)

مخلصیم
مطالب
نادیده گرفته شدن فایل gitignore توسط Visual Studio
در مورد کاربرد فایل  gitignore . می‌توانید این پست را مطالعه فرمایید.

در هنگام اولین بارگزاری پروژه در مخزن Git ، گاها دیده می‌شود که Visual Studio  فایل gitignore . ایی را که شما آماده کرده‌اید، نادیده گرفته و فایل gitignore . پیش فرض خود را در مخزن Push می‌کند. در این پست یک راه حل ممکن برای حل این مشکل ارائه می‌دهیم.

1- در Visual Studio  از مسیر File->Add to Source Control و با انتخاب Git پروژه را آماده کنید:



2- بدون هیچ تغییری، پروژه را ببندید و در مسیر ذخیره سازی پروژه، به پوشه‌ی git . (مخفی است ( وارد شوید.
3- فایل
ms-persist.xml را حذف کنید.
4- پروژه را باز کنید. در قسمت
Team Explorer وارد Setting شوید. در قسمت Ignore File، فایل gitignore . را مطابق نیاز خود ویرایش و ذخیره کنید.
5- در قسمت
Team Explorer وارد قسمت Changes شوید. یک نام مناسب را وارد و سپس Commit  کنید.



6 - در بالا با کلیک روی sync به قسمت commits unsync وارد خواهید شد. در این جا آدرس مخزن پروژه را وارد کنید و گزینه Publish را وارد کنید.

7- تا این مرحله فایل  gitignore مورد نظر شما وارد مخزن شده است. برای بارگزاری مابقی پروژه به ترتیب مراحل 1 ، 5 و سپس 6 را تکرار کنید با این تفاوت که در مرحله 6 نیازی به Publish نبوده و صرفا انتخاب گزینه  sync کافی است.

مطالب
روش نامگذاری Smurf ایی!
اگر به یک سری از کتابخانه‌ها دقت کنید، تمام کلاس‌های آن‌ها دارای یک پیشوند تکراری هستند؛ مثلا SmurfXMLDataRow، SmurfXMLElement و الی آخر در مورد تمام کلاس‌های موجود در پروژه. به این رویه «Smurf Naming Convention» گفته می‌شود!
در این نوع کتابخانه‌ها زمانیکه کاربری بر روی دکمه‌ای کلیک می‌کند، SmurfAccountView اطلاعات SmurfAccountDTO را به SmurfAccountController منتقل می‌کند. در ادامه از خاصیت SmurfID دریافتی، مقدار SmurfOrderHistory دریافت شده و به SmurfHistoryReportingView جهت نمایش ارسال خواهد شد. اگر استثنای SmurfErrorEvent رخ دهد، توسط SmurfErrorLogger در فایلی به نام log/smurf/smurflog.log ثبت خواهد شد.

کلمه Smurf هم از شخصیتی کارتونی به همین نام اخذ شده است که در زبان مخصوص آن‌ها اکثر افعال و نام‌ها از کلمه Smurf مشتق می‌شود! برای مثال در مورد ماهیگیری کردن در یک رودخانه عنوان می‌کنند «We're going smurfing on the River Smurf today».


خوب، چکار باید کرد؟ روش صحیح معرفی نام یک شرکت در حین طراحی و نامگذاری کلاس‌های یک کتابخانه چیست؟
در مطلب بسیار جامع و عالی «اصول و قراردادهای نام‌گذاری در دات‌نت» عنوان شده است که اساس نام‌گذاری فضاهای نام باید از قاعده زیر پیروی کند:
<Company>.<Technology|Produt|Project>[.<Feature>][.<SubNamespace>]
مثلا مایکروسافت یکبار فضای نام Microsoft.Reporting.WebForms را تعریف کرده است و ... همین! دیگر به ابتدای هر کلاسی در این کتابخانه، پیشوند Microsoft یا MS و امثال آن اضافه نشده است تا بر روی اعصاب و روان استفاده کننده تاثیر منفی داشته باشد.

 
مطالب
افزونه فارسی به پارسی برای word 2007

افزونه‌ی زیر کار مشخص کردن کلماتی که قابل تبدیل از فارسی به پارسی هستند را انجام می‌دهد (به صورت خودکار و در زمان تایپ) و همچنین امکان تبدیل خودکار آنها را نیز فراهم می‌کند.



برای نصب آن باید به ترتیب زیر عمل کنید (مهم)
لطفا این سه مرحله را به ترتیب انجام دهید در غیر اینصورت نتیجه نخواهید گرفت.
همچنین بدیهی است که برنامه باید با دسترسی admin نصب شود.
و همانطور که در عنوان این موضوع نیز ذکر گردید، این افزونه تنها برای MS-Word 2007 طراحی شده است.

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

پس از نصب به گزینه‌ی word options مراجعه کنید: (جهت اطمینان از نصب آن)



این افزونه را باید در لیست مربوطه مشاهده نمائید:



هر زمانیکه مایل به عدم استفاده از آن باشید با کلیک بر روی دکمه Go ، در صفحه بعد می‌توان افزونه را حذف کرد:



مثالی دیگر از نحوه‌ی بکارگیری این افزونه: