نظرات مطالب
استفاده از Web API در ASP.NET Web Forms
- بله. گروه Web API و EF را در سایت پیگیری کنید.
- Web API یک بحث سمت سرور است. به آن به زبان ساده به چشم یک وب سرویس مدرن نگاه کنید. برای نمونه بجای وب‌متدهای استاتیک صفحات aspx یا فایل‌های ashx یا asmx و حتی سرویس‌های WCF از نوع REST و امثال آن، بهتر است از Web API استفاده کنید.  
- برای نمونه پایه مباحثی مانند Forms Authentication در اینجا هم کاربرد دارد (البته این یک نمونه است).
- برای کار با Web API الزاما نیازی به ASP.NET ندارید (نه وب فرم‌ها و نه MVC)؛ به هیچکدام از نگارش‌های آن. سمت کاربر آن AngularJS و سمت سرور آن Web API باشد. کار می‌کند. (اهمیت این مساله در اینجا است که الان می‌شود یک فریم ورک جدید توسعه‌ی برنامه‌های وب را کاملا مستقل از وب فرم‌ها و MVC طراحی کرد)
نظرات مطالب
روش از کار انداختن صفحه‌ی Add service reference در VS.NET
با درود و خسته نباشید
استاد گرامی پرسشی داشتم
ما در سازمانمان نرم افزاری داریم که کاربران آن در Active directory تعریف شده اند.
برنامه با وب سرویس در ارتباط است که در یک سروری قرار گرفته است که آن سرور با یک سرور دیگر از طریق کابل شبکه در ارتباط است.
سرور دوم سروری است که پایگاه داده روی آن قرار گرفته است.
با توجه به اینکه با WCF کاربر جاری برنامه را می توان به دست آورد؛ ما کاربر جاری را تا سطح سرور 1 می آوریم ولی برای ارسال آن به اس کیو ال دو راه حل داریم.
راهی که هم اکنون از آن استفاده می کنیم این است که Connection string مان تک کاربره است و دیگر اینکه هم اکنون که کاربر جاری را داریم همان را با Connection string به سمت SQL بفرستیم و که در نتیجه گزارش گیری و مانیتورینگ بسیار خوبی خواهیم داشت. ولی باید همه کاربران در SQL تعریف شوند چون سرور پایگاه داده به دومین متصل نیست.

به نظر شما در صورتی که سرورهای نسبتاً خوبی از لحاظ سخت افزاری داشته باشیم و کاربرانی در حدود 2000 نفر به طور کلی و 200 نفر همزمان داشته باشیم، Connection string تک کاربره بهتر است یا چند کاربره؟

با سپاس فراوان
نظرات نظرسنجی‌ها
آخرین باری که یک کتاب فارسی را در زمینه‌ی دات نت خریدید، کی بوده؟

اصولا خوندن کتاب کاغذی را نسبت به PDF   ترجیح می‌دم اگه فارسی هم باشه چه بهتر

به نظر من کتاب‌های فارسی :

اکثرا ترجمه روانی ندارند یا بعضی از لغت‌ها بهتره ترجمه نشه که ترجمه شده (بعضی وقت‌ها فکر می‌کنی گوگل ترجمه کرده یا یک فرد غیر متخصص که تجربه ای در این رشته نداره)

این کتاب‌ها بومی نشده اند (اگه تالیف یک کتاب سخته حداقل می‌تونه لابه لای مطالب اون نکات و یا ابزارهایی که برای خواننده ایرانی مهم است باشه )

نمونه بد اون

مثلا کتاب Visual C# 2010 ترجمه احمد پهلوان انتشارات ناقوس که فصل آخر اون که راجب وب سرویس هست هر جایی که باید مینوشته WCF به اشتباه نوشته WPF و خیلی مشکلات دیگه

و یه نمونه خوب که مشکلات بالا رو نداره

سری آموزشی ASP.NET MVC وحید نصیری که اگه چاپ شده بود حتما می‌خریدمش 

مطالب
پیاده سازی InstanceProvider برای سرویس های WCF
اگر قصد داشته باشیم که تزریق وابستگی (Dependency Injection) را برای سرویس‌های WCF پیاده سازی کنیم نیاز به یک  Instance Provider  سفارشی داریم. در ابتدا باید سرویس‌های مورد نظر را در یک Ioc Container رجیستر نماییم سپس با استفاده از InstanceProvider عملیات وهله سازی از سرویس‌ها همراه با تزریق وابستگی انجام خواهد گرفت. فرض کنید سرویسی به صورت زیر داریم:
[ServiceBehavior( IncludeExceptionDetailInFaults = true)]
    public class BookService : IBookService
    {
        public BookService(IBookRepository bookRepository)
        {
            Repository = bookRepository;    
        }

        public IBookRepository Repository 
        {
            get;
            private set;
        }

        public IList<Entity.Book> GetAll()
        {
            return Repository.GetAll();
        }
     
    }
همانطور که می‌بینید برای عملیات وهله سازی از این سرویس نیاز به تزریق کلاس BookRepository  است که این کلاس باید ابنترفیس IBookRepository را پیاده سازی کرده باشد. برای این که Instance Provider  ما بتواند عملیات تزریق وابستگی را به درستی انجام دهد، ابتدا باید BookRepository و BookService را به یک IocContainer (در این جا از الگوی ServiceLocator و UnityContainer   استفاده کردم) رجیستر نماییم . به صورت زیر:

var container = new UnityContainer();

      container.RegisterType<IBookRepository, BookRepository>();
      container.RegisterType<BookService, BookService>();

ServiceLocator.SetLocatorProvider(new ServiceLocatorProvider(() => { return container; }));
حال باید InstanceProvider را به صورت  زیر ایجاد نمایم:
 public class UnityInstanceProvinder : IInstanceProvider
    {
        private Type serviceType;

        public UnityInstanceProvinder( Type serviceType )
        {
            this.serviceType = serviceType;
        }

        public object GetInstance( InstanceContext instanceContext, Message message )
        {            
            return ServiceLocator.Current.GetInstance( serviceType );
        }

        public object GetInstance( InstanceContext instanceContext )
        {
            return GetInstance( instanceContext, null );
        }

        public void ReleaseInstance( InstanceContext instanceContext, object instance )
        {
            if ( instance is IDisposable )
            {
                ( ( IDisposable )instance ).Dispose();
            }
        }
    }

با پیاده سازی متد‌های اینترفیس IInstanceProvider می‌توان عملیات وهله سازی سرویس‌های WCF را تغییر داد. متد GetInstance همین کار را برای ما انجام خواهد داد. در این متد ما با توجه به نوع ServiceType سرویس مورد نظر را از ServiceLocator تامین خواهیم کرد. چون وابستگی‌های سرویس هم در IOC Cotnainer موجود است در نتیجه سرویس به درستی وهله سازی خواهد شد. از آن جا که در WCF  عملیات وهله سازی از سرویس‌ها به طور مستقیم به نوع سرویس بستگی دارد، هیچ نیازی به نوع Contract مربوطه نیست. در نتیجه Service Type به صورت مستقیم در اختیار این کلاس قرار خواهد گرفت. مرحله آخر معرفی IInstanceProvider به عنوان یک Service Behavior است. برای این کار کد‌های زیر را در کلاسی به نام UnityInstanceProviderContext کپی نمایید:
public class UnityInstanceProviderContext : IServiceBehavior
    {
        public void AddBindingParameters( ServiceDescription serviceDescription , ServiceHostBase serviceHostBase , Collection<ServiceEndpoint> endpoints , BindingParameterCollection bindingParameters )
        {
        }

        public void ApplyDispatchBehavior( ServiceDescription serviceDescription , ServiceHostBase serviceHostBase )
        {
            serviceHostBase.ChannelDispatchers.ToList().ForEach( channelDispatcherBase =>
                {
                    var channelDispatcher = ( channelDispatcherBase as ChannelDispatcher );
                    if ( channelDispatcher != null )
                    {
                        channelDispatcher.Endpoints.ToList().ForEach( endpoint =>
                            {
                                endpoint.DispatchRuntime.InstanceProvider = new UnityInstanceProvinder( serviceDescription.ServiceType );
                            } );
                    }
                } );
        }

        public void Validate( ServiceDescription serviceDescription , ServiceHostBase serviceHostBase )
        {
        }
    }
در متد ApplyDispatchBehavior همان طور دیده می‌شود به ازای تمام EndPoint‌های هر ChannelDispatcher یک نمونه از کلاس UnityInstanceProvider به همراه پارامتر سازنده آن که نوع سرویس مورد نظر است به خاصیت InstanceProvider در DispatchRuntime معرفی می‌گردد.
در هنگام هاست سرویس مورد نظر هم باید تمام این عملیات به عنوان یک Behavior در اختیار ُService Host قرار گیرد.همانند نمونه کد ذیل:
using (ServiceHost host = new ServiceHost(typeof(BookService)))
{
                    host.Description.Behaviors.Add( new UnityInstanceProviderContext() );
 }
مطالب
محدود کردن درخواست های Asp.Net Web Api بر اساس Client IP
در بسیاری از سناریو‌ها این موضوع مطرح می‌شود که سرویس‌های طراحی شده بر اساس Asp.Net Web Api، فقط به یک سری آی پی‌های مشخص سرویس دهند. برای مثال اگر Ip کلاینت در لیست کلاینت‌های دارای لایسنس خریداری شده بود، امکان استفاده از سرویس میسر باشد؛ در غیر این صورت خیر. بسته به نوع پیاده سازی سرویس‌های Web api، پیاده سازی این بخش کمی متفاوت خواهد شد. در طی این پست این موضوع را برای سه حالت IIs Host  و SelfHost و Owin Host بررسی می‌کنیم.
در اینجا قصد داریم حالتی را پیاده سازی نماییم که اگر درخواست جاری از سوی کلاینتی بود که Ip آن در لیست Ip‌های غیر مجاز قرار داشت، ادامه‌ی عملیات متوقف شود.

IIS Hosting:
حالت پیش فرض استفاده از سرویس‌های Web Api همین گزینه است؛ وابستگی مستقیم به System.Web . در مورد مزایا و معایب آن بحث نمی‌کنیم اما اگر این روش را انتخاب کردید تکه کد زیر این کار را برای ما انجام می‌دهد:
if (request.Properties.ContainsKey["MS_HttpContext"]) 
{
    var ctx = request.Properties["MS_HttpContext"] as HttpContextWrapper;
    if (ctx != null)
    {
        var ip = ctx.Request.UserHostAddress;       
    }
}
برای بدست آوردن شی HttpContext می‌توان آن را از لیست Properties‌های درخواست جاری به دست آورد. حال کد بالا را در قالب یک Extension Method در خواهیم آورد؛ به صورت زیر:

public static class HttpRequestMessageExtensions
{
    private const string HttpContext = "MS_HttpContext";

    public static string GetClientIpAddress(this HttpRequestMessage request)
    {
        if (request.Properties.ContainsKey(HttpContext))
        {
            dynamic ctx = request.Properties[HttpContext];
            if (ctx != null)
            {
                return ctx.Request.UserHostAddress;
            }
        }      
        return null;
    }
}

Self Hosting:

در حالت Self Host می‌توان عملیات بالا را با استفاده از خاصیت RemoteEndpointMessageProperty  انجام داد که تقریبا شبیه به حالت Web Host است. مقدار این خاصیت نیز در شی جاری HttpRequestMessage وجود دارد. فقط باید به صورت زیر آن را واکشی نماییم:
if (request.Properties.ContainsKey[RemoteEndpointMessageProperty.Name]) 
{
    var remote = request.Properties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;

    if (remote != null)
    {
        var ip = remote.Address;        
    }
}
خاصیت RemoteEndpointMessageProperty  به تمامی درخواست‌ها وارده در سرویس‌های WCF چه در حالت استفاده از Http و چه در حالت Tcp اضافه می‌شود و در اسمبلی System.ServiceModel نیز می‌باشد. ار آنجا که Web Api از هسته‌ی WCF استفاده می‌کند (WCF Core) در نتیجه می‌توان از این روش استفاده نمود. فقط باید اسمبلی System.ServiceModel را به پروژه‌ی خود اضافه نمایید.

ترکیب حالت‌های قبلی:
اگر می‌خواهید کد‌های نوشته شده شما وابستگی به نوع هاست پروژه نداشته باشد، یا به معنای دیگر، در هر دو حالت به درستی کار کند می‌توانید به روش زیر حالت‌های قبلی را با هم ترکیب کنید. 
»در این صورت دیگر نیازی به اضافه کردن اسمبلی System.ServiceModel  نیست.
public static class HttpRequestMessageExtensions
{
    private const string HttpContext = "MS_HttpContext";
    private const string RemoteEndpointMessage = "System.ServiceModel.Channels.RemoteEndpointMessageProperty";

    public static string GetClientIpAddress(this HttpRequestMessage request)
    {
        if (request.Properties.ContainsKey(HttpContext))
        {
            dynamic ctx = request.Properties[HttpContext];
            if (ctx != null)
            {
                return ctx.Request.UserHostAddress;
            }
        }

        if (request.Properties.ContainsKey(RemoteEndpointMessage))
        {
            dynamic remoteEndpoint = request.Properties[RemoteEndpointMessage];
            if (remoteEndpoint != null)
            {
                return remoteEndpoint.Address;
            }
        }

        return null;
    }
}
مرحله بعدی طراحی یک DelegatingHandler جهت استفاده از IP به دست آمده است .
 
public class MyHandler : DelegatingHandler
{
 private readonly HashSet<string> deniedIps;

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {

      if (deniedIps.Contains(request.GetClientIpAddress()))
        {            
            return Task.FromResult( new HttpResponseMessage( HttpStatusCode.Unauthorized ) );
        }

        return base.SendAsync(request, cancellationToken);
    }
}

Owin :

زمانی که از Owin   برای هاست سرویس‌های Web Api خود استفاده می‌کنید کمی روال انجام کار متفاوت خواهد شد. در این مورد نیز می‌توانید از DelegatingHandler‌ها استفاده کنید. معرفی DelegatingHandler طراحی شده به Asp.Net PipeLine به صورت زیر خواهد بود:
public class Startup
    {
        public void Configuration( IAppBuilder appBuilder )
        {     
            var config = new HttpConfiguration();
                 
            var routeHandler = HttpClientFactory.CreatePipeline( new HttpControllerDispatcher( config ), new DelegatingHandler[] 
            {
                new MyHandler(),
            } );
      
            config.Routes.MapHttpRoute(
                name: "Default",
                routeTemplate: "{controller}/{action}",
                defaults: null,
                constraints: null,
                handler: routeHandler
            );            
           
            config.EnsureInitialized();
         
            appBuilder.UseWebApi( config );         
        }
    }
اما نکته ای را که باید به آن دقت داشت، این است که یکی از مزایای استفاده از Owin، یکپارچه سازی عملیات هاستینگ قسمت‌های مختلف برنامه است. برای مثال ممکن است قصد داشته باشید که بخش هایی که با Asp.Net SignalR نیز پیاده سازی شده‌اند، قابلیت استفاده از کد‌های بالا را داشته باشند. در این صورت بهتر است کل عملیات بالا در قالب یک Owin Middleware عمل نماید تا تمام قسمت‌های هاست شده‌ی برنامه از کد‌های بالا استفاده نمایند؛ به صورت زیر:
public class IpMiddleware : OwinMiddleware
{
    private readonly HashSet<string> _deniedIps;

    public IpMiddleware(OwinMiddleware next, HashSet<string> deniedIps) :
        base(next)
    {
        _deniedIps = deniedIps;
    }

    public override async Task Invoke(OwinRequest request, OwinResponse response)
    {
        var ipAddress = (string)request.Environment["server.RemoteIpAddress"];

        if (_deniedIps.Contains(ipAddress))
        {
            response.StatusCode = 403;
            return;
        }

        await Next.Invoke(request, response);
    }
}
برای نوشتن یک Owin Middleware کافیست کلاس مورد نظر از کلاس OwinMiddleware ارث ببرد و متد Invoke را Override کنید.  لیست Ip‌های غیر مجاز، از طریق سازنده در اختیار Middleware قرار می‌گیرد. اگر درخواست مجاز بود از طریق دستور Next.Invoke(request,response) کنترل برنامه به مرحله بعدی منتقل می‌شود در غیر صورت عملیات با کد 403 متوقف می‌شود.
در نهایت برای معرفی این Middleware طراحی شده به Application، مراحل زیر را انجام دهید.
public class Startup
    {
        public void Configuration( IAppBuilder appBuilder )
        {       
           var config = new HttpConfiguration();                      

           var deniedIps = new HashSet<string> {"192.168.0.100", "192.168.0.101"}; 
          
app.Use(typeof(IpMiddleware), deniedIps); appBuilder.UseWebApi( config ); } }
مطالب
Data Contracts and Circular References
تشریح مسئله : در DataContractSerializer  قابلیتی به عنوان سریالایز کردن object‌ها به صورت درختی وجود داردکه اصطلاحا به اون  Circular References گفته می‌شود در این پست قصد دارم روش پیاده سازی، به همراه مزایای استفاده از این روش رو توضیح بدم.
نکته : آشنایی با مفاهیم اولیه WCF برای درک بهتر مطالب الزامی است.
در ابتدا لازم است تا مدل برنامه را تعریف کنیم. ابتدا یک پروژه از نوع WCF Service Application ایجاد کنید و مدل زیر را بسازید.

#Employee
   [DataContract]
    public class Employee
    {
        [DataMember]
        public string Name { get; set; }

        [DataMember]
        public Employee Manager { get; set; }
    }
#Department
[DataContract]
    public class Department
    {
        [DataMember]
        public string DeptName { get; set; }

        [DataMember]
        public List<Employee> Staff { get; set; }
    }
در مدل Employee یک خاصیت از نوع خود کلاس Employee وجود دارد که برای پیاده سازی مدل به صورت درختی است. در مدل Department هم لیستی از کارمندان دپارتمان را ذخیره می‌کنیم و قصد داریم این مدل رو از سمت سرور به کلاینت انتقال دهیم و نوع سریالایز کردن WCF رو در این مورد مشاهده کنیم. ابتدا سرویس و Contract مربوطه را می‌نویسیم.

#Contract
  [ServiceContract]
    public interface IDepartmentService
    {
        [OperationContract]
        Department GetOneDepartment();
    }
#Service
public class DepartmentService : IDepartmentService
    {
        public Department GetOneDepartment()
        {
            List<Employee> listOfEmployees = new List<Employee>();

              var masoud = new Employee() { Name = "Masoud" };
              var saeed = new Employee() { Name = "Saeed", Manager = masoud };
              var peyman = new Employee() { Name = "Peyman", Manager = saeed };
              var mostafa = new Employee() { Name = "Mostafa", Manager = saeed };

              return new Department() { DeptName = "IT", Staff = new List<Employee>() { masoud, saeed, peyman, mostafa } };
        }
    }
همانطور که در سرویس بالا مشخص است لیستی از کارمندان ساخته شده که خود این لیست به صورت درختی است و بعضی از کارمندان به عنوان مدیر کارمند دیگر تعیین شد است. حال برای دریافت اطلاعات سمت کلاینت یک پروژه از نوع Console ایجاد کنید و از روش AddServiceReference سرویس مورد نظر را اضافه کنید و کد‌های زیر را در کلاس Program کپی کنید.
 class Program
    {
        static void Main( string[] args )
        {
            DepartmentServiceClient client = new DepartmentServiceClient();

            var result = client.GetOneDepartment();
            WriteDataToFile( result );

            Console.ReadKey();
        }

        private static void WriteDataToFile( Department data )
        {
            DataContractSerializer dcs = new DataContractSerializer( typeof( Department ) );
            var ms = new MemoryStream();
            dcs.WriteObject( ms, data );
            ms.Seek( 0, SeekOrigin.Begin );
            var sr = new StreamReader( ms );
            var xml = sr.ReadToEnd();
            string filePath = @"d:\\data.xml";
            if ( !File.Exists( filePath ) )
            {
                File.Create( filePath );
            }         
                using ( TextWriter writer = new StreamWriter( filePath ) )
                {
                    writer.Write( xml );
                }                      
        }
یک متد به نام WriteDataToFile نوشتم که اطلاعات Department رو به فرمت Xml در فایل ذخیره می‌کند. بعد از اجرای برنامه خروجی مورد نظر در فایل Xml به صورت زیر است.
<Department xmlns="http://schemas.datacontract.org/2004/07/Service" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <Name>IT</Name>
  <Staff>
    <Employee>
      <Manager i:nil="true"/>
      <Name>Masoud</Name>
    </Employee>
    <Employee>
      <Manager>
        <Manager i:nil="true"/>
        <Name>Masoud</Name>
      </Manager>
      <Name>Saeed</Name>
    </Employee>
    <Employee>
      <Manager>
        <Manager>
          <Manager i:nil="true"/>
          <Name>Masoud</Name>
        </Manager>
        <Name>Saeed</Name>
      </Manager>
      <Name>Peyman</Name>
    </Employee>
    <Employee>
      <Manager>
        <Manager>
          <Manager i:nil="true"/>
          <Name>Masoud</Name>
        </Manager>
        <Name>Saeed</Name>
      </Manager>
      <Name>Mostafa</Name>
    </Employee>
  </Staff>
</Department>
در فایل بالا مشاهده می‌کنید که تعداد تکرار Masoud به اندازه تعداد استفاده اون در Department است. در این قسمت قصد داریم که از Circular Referencing موجود در DataContractSerializer استفاده کنیم. برای این کار کافیست از خاصیت IsReference موجود در DataContract استفاده کنیم. پس مدل Employee به صورت زیر تغییر میباید:
   [DataContract( IsReference = true )]
    public class Employee
    {
        [DataMember]
        public string Name { get; set; }

        [DataMember]
        public Employee Manager { get; set; }
    }
پروژه رو دوباره Run کنید و فایل xml ساخته شده به صورت زیر تغییر می‌کند.
<Department xmlns="http://schemas.datacontract.org/2004/07/Service" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
  <Name>IT</Name>
  <Staff>
    <Employee z:Id="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
      <Manager i:nil="true"/>
      <Name>Masoud</Name>
    </Employee>
    <Employee z:Id="i2" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
      <Manager z:Ref="i1"/>
      <Name>Saeed</Name>
    </Employee>
    <Employee z:Id="i3" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
      <Manager z:Ref="i2"/>
      <Name>Peyman</Name>
    </Employee>
    <Employee z:Id="i4" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
      <Manager z:Ref="i2"/>
      <Name>Mostafa</Name>
    </Employee>
  </Staff>
</Department>
کاملا واضح است که تعداد Masoud به عنوان Employee فقط یک بار است و از z:ref برای ارتباط بین Object‌ها استفاده می‌شود. در این روش فقط یک بار هر object سریالاز می‌شود و هر جا که نیاز به استفاده از object مربوطه باشد فقط یک ارجاع به آن خواهد شد.
مزایا :استفاده از این روش در هنگام عمل سریالایز داده‌های زیاد و زمانی که  تعداد Object‌های موجود در ObjectGraph  زیاد باشد باعث افزایش کارایی و سرعت انجام عملیات سریالایز می‌شود.
مطالب
آشنایی با TransactionScope
TransactionScope روشی برای پیاده سازی تراکنش در .Net است که برای اولین بار در دات نت 2 معرفی شده است. روش پیاده سازی آن بسیار ساده است و همین سادگی و راحتی کار با اون باعث شده است که خیلی از برنامه نویس‌ها رو متمایل به خودش کنه.  در ادامه به روش استفاده و مزایا و معایب این روش برای پیاده سازی تراکنش‌ها می‌پردازیم.
این روش دارای تمام خواص یک تراکنش است(اصطلاحا به این خواص  ACID Properties گفته میشود)
1-Atomic : به این معناست که تمام دستورات بین بلاک (دستورات SQL و سایر عملیات) باید به صورت عملیات اتمی  کار کنند. یعنی یا تمام عملیات موفقیت آمیز است یا همه با شکست روبرو می‌شوند.
2 - Consistent: به این معناست که اگر تراکنش موفقیت آمیز بود پایگاه داده  باید در شروع تراکنش بعدی تغییرات لازم رو انجام داده باشد و در غیر این صورت پایگاه داده باید به حالت قبل از شروع تراکنش برگردد.
3- Isolated: اگر چند تا تراکنش هم زمان شروع شوند اجرای هیچ کدوم از اون‌ها نباید بر اجرای بقیه تاثیر بزاره.
4- Durable: یعنی تغییرات حاصل شده بعد از اتمام تراکنش باید دائمی باشند.

روش کار به این صورت است تمام کارهایی که قصد داریم در طی یک تراکنش انجام شوند باید در یک بلاک قرار بگیرند و تا زمانی که متد  Complete فراخوانی شود. در این بلاک شما هر عملیاتی رو که به عنوان جزئی از تراکنش می‌دونید قرار بدید. در صورتی که کنترل اجرا به فراخوانی دستور Complete برسه تمام موارد قبل از این دستور Commit  می‌شوند در غیر این صورت RollBack.
به مثال زیر دقت کنید.
ابتدا به پروژه مربوطه باید اسمبلی System.Transaction رو اضافه کنید.
using ( TransactionScope scope = new TransactionScope() )
  {
       //Statement1
       //Statement2
       //Statement3
         scope.Complete();
    }
تمام دستوراتی که در این بلاک نوشته شوند بعد از فراخوانی دستور scope.Complete اصطلاحا Commit می‌شوند. اگر به هر دلیلی فراخوانی دستورات به scope.Complete  نرسد عمل RollBack انجام می‌شود. در نتیجه برای این که عمل RollBack رو انجام دهید بهتره که قبل از دستور  Complete یک Exception رو پرتاب کنید که باعث فراخوانی Dispose می‌شود. کد زیر
using ( System.Transactions.TransactionScope scope = new System.Transactions.TransactionScope() )
            {
                if ( result == 0 )
                {
                    throw new ApplicationException();
                }
                scope.Complete();
            }
نکته حائز اهمیت این است که اگر در هنگام اجرای برنامه به این روش به خطای
MSDTC on server {} is unavailable
برخوردید باید سرویس MSDTC رو Start کنید.برای این کار باید سرویس Distributed Transaction Coordinator رو از لیست سرویس‌های ویندوز پیدا کنید و بر روی اون راست کلیک کرده و دکمه Start رو بزنید.
نکته 1: میزان Timeout در این تراکنش‌ها چه قدر است؟
برای بدست آوردن مقدار Timeout در این گونه تراکنش‌ها می‌توانید از کلاس TransactionManager استفاده کنید. به صورت زیر :

var defaultTimeout = TransactionManager.DefaultTimeout
var maxTimeout = TransactionManager.MaximumTimeout
مقدار پیش فرض برای DefaultTimeout یک دقیقه است و برای MaximumTimeout ده دقیقه است. البته خاصیت‌های بالا به صورت فقط خواندنی هستند و نمی‌تونید از این راه مقدار Timeout هر تراکنش را افزایش یا کاهش دهیم. برای این کار بهتره از روش زیر استفاده کنیم.
TransactionOptions option = new TransactionOptions(); 
 option.Timeout = TimeSpan.MaxValue;

  using ( System.Transactions.TransactionScope scope = new System.Transactions.TransactionScope(TransactionScopeOption.Required ,option) ) { scope.Complete(); }
توضیح درباره انواع TransactionScopeOption
1 - Required  : یعنی نیاز به تراکنش وجود دارد. در صورتی که تراکنش در یک تراکنش دیگر شروع شود نیاز به ساختن تراکنش جدید نیست و از همان تراکنش قبلی برای این کار استفاده می‌شود.
2 - RequiresNew: در هر صورت برای محدوده یک تراکنش تولید می‌شود.
3- Suppress : به عنوان محدوه تراکنش در نظر گرفته نمی‌شود.
using(TransactionScope scope1 = new TransactionScope())
{
     try
     {          
          using(TransactionScope scope2 = new  TransactionScope(TransactionScopeOption.Suppress))
          {
               //به دلیل استفاده از Suppress این محدوده خارج از تراکنش محسوب می‌شود
          }
          //شروع محدوده تراکنش
   }
     catch
     {}
   //Rest of scope1
}
مزایا استفاده از این روش
1-این روش از تراکنش‌های توزیع شده پشتیبانی می‌کند . یعنی می‌تونید از چند تا منبع داده استفاده کنید یا می‌تونید از یک تراکنش چند تا Connection به یک منبع داده باز کنید.(استفاده از چند تاconnection در طی یک تراکنش)
using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
{
    string strCmd = "SQL to Execute";
    conn = new SqlClient.SqlConnection("Connection to DB1");
    conn.Open()
    objCmd = new SqlClient.SqlCommand(strCmd, conn);
    objCmd.ExecuteNonQuery();
    string strCmd2 = "SQL to Execute";
    conn2 = new SqlClient.SqlConnection("Connection to DB2");
    conn2.Open()
    objCmd2 = new SqlClient.SqlCommand(strCmd2, conn2);
    objCmd2.ExecuteNonQuery();
}
2- پیاده سازی این روش  واقعا راحت است .
3- با DataProvider‌های متفاوت نظیر Oracle و OleDb و ODBC سازگار است.
4- از تراکنش‌های تو در تو به خوبی پشتیبانی میکنه(Nested Transaction)
using(TransactionScope scope1 = new TransactionScope()) 
{ 
     using(TransactionScope scope2 = new  TransactionScope(TransactionScopeOption.Required)) 
     {
     ...
     } 

     using(TransactionScope scope3 = new TransactionScope(TransactionScopeOption.RequiresNew)) 
     {
     ...
     } 

     using(TransactionScope scope4 = new   TransactionScope(TransactionScopeOption.Suppress)) 
    {
     ...
    } 
}
5- به خوبی توسط سرویس‌های WCF پشتیبانی می‌شود و برای سیستم‌های SOA مبتنی بر WCF مناسب است.معایب :
*استفاده از این روش در سیستم هایی که تعداد کاربران آنلاین آن زیاد است و هم چنین تعداد تراکنش‌های موجود نیز در سطح سیستم خیلی زیاد باشه مناسب نیست.
*تراکنش‌های استفاده شده از این روش کند هستند.(مخصوصا که تراکنش در سطح دیتابیس با تعداد و حجم داده زیاد باشه)
امکان تغییر IsolationLevel در طی انجام یک تراکنش امکان پذیر نیست.
(به شخصه مواد * رو در سطح یک پروژه با شرایط کاربران  و حجم داده زیاد تست کردم و نتیجه مطلوب حاصل نشد)

موفق باشید.
نظرات مطالب
خودکارسازی فرآیند نگاشت اشیاء در AutoMapper
ممنون از پاسختون؛
اتفاق عجیبی رخ میده که متوجه نمیشم ؛ کلاسهای ViewModel در پروژه سرویس تعریف شدن  و از داخل سرویس خروجی را  مپ میکنم و بازگشت میدم.
به این صورتی که فرمودید عمل کردم؛ حالا عمل نگاشت و مپ در سرویس به درستی عمل میکنه ولی عمل نگاشت و مپ داخل کنترلها که داخل پروژه وب هستند دیگر کار نمیکند قبل از اینکه این کارو بکنم دقیقا عکس  این اتفاق رخ میداد یعنی عمل مپ در پروژه وب و کنترلها به درستی انجام میشد ولی در داخل سرویس با خطا مواجه میشد. به نظر میرسه فقط عملیات مپ اسمبلی که معرفی شده به درستی کار میکند!
تنظیمات تزریق وابستگی اتومپر داخل پروژه MVC انجام میشه و در پروژه سرویس و کنترل های MVC  مپر تزریق میشه. با سپاس.