مایکرو سرویسها - قسمت 1 - معرفی
- اندازه سرویسها در این دو متفاوت میباشد در مایکرو سرویسها اندازه یک سرویسها کوچکتر از اندازه سرویسها در SOA میباشد
- سرویها در مایکرو سرویس میتوانند کاملا مستقل از هم قابل استقرار باشندو مکانیزم استقار بصورت خودکار میباشد درحالی که در SOA این امکان وجود ندارد
- در SOA برای بررسی قوانین کسب و کار و ادغام سیستمهای یکپارچه تمرکزبر روی ESB می باشد ، در حالی که این امر در مایکرو سرویسها یک anti pattern به شمار میآید و دیدگاه آنها عدم انتقال قوانین کسب کار به مکانیزم ارتباطی میباشد (smart endpoints and dumb pipe)
OData چهار قسمت اصلی دارد:
- OData data model که یک راه عمومی برای مدیریت و توصیف دادهها را فراهم مینماید
- OData protocol که به کلاینت اجازه ایجاد درخواست و پاسخ از سرویس دهنده OData را میدهد.
- OData client libraries که امکان ساخت سادهتر نرم افزارها برای دسترسی به دادهها با قرارداد OData را میدهد.
- OData service سرویس دهنده و امکان دسترسی به دادهها را فراهم میسازد.
- ساده و انعطاف پذیر
- سورس باز بودن
- امکان استفاده در سیستمهای با دادههای رابطه ای و غیر رابطه ای
- امکان استفاده از دادهها با منابع ای که آدرس پذیر هستند یعنی دسترسی از طریق Url
- امکان دسترسی هر نوع گیرنده ای به داده ها
- امکان نمایش خروجی با فرمت Json یا Xml
- ...
معماری N-Tier چالشهای بخصوصی را برای قابلیتهای change-tracking در EF اضافه میکند. در ابتدا دادهها توسط یک آبجکت EF Context بارگذاری میشوند اما این آبجکت پس از ارسال دادهها به کلاینت از بین میرود. تغییراتی که در سمت کلاینت روی دادهها اعمال میشوند ردیابی (track) نخواهند شد. هنگام بروز رسانی، آبجکت Context جدیدی برای پردازش اطلاعات ارسالی باید ایجاد شود. مسلما آبجکت جدید هیچ چیز درباره Context پیشین یا مقادیر اصلی موجودیتها نمیداند.
در نسخههای قبلی Entity Framework توسعه دهندگان با استفاده از قالب ویژه ای بنام Self-Tracking Entities میتوانستند تغییرات موجودیتها را ردیابی کنند. این قابلیت در نسخه EF 6 از رده خارج شده است و گرچه هنوز توسط ObjectContext پشتیبانی میشود، آبجکت DbContext از آن پشتیبانی نمیکند.
در این سری از مقالات روی عملیات پایه CRUD تمرکز میکنیم که در اکثر اپلیکیشنهای n-Tier استفاده میشوند. همچنین خواهیم دید چگونه میتوان تغییرات موجودیتها را ردیابی کرد. مباحثی مانند همزمانی (concurrency) و مرتب سازی (serialization) نیز بررسی خواهند شد. در قسمت یک این سری مقالات، به بروز رسانی موجودیتهای منفصل (disconnected) توسط سرویسهای Web API نگاهی خواهیم داشت.
بروز رسانی موجودیتهای منفصل با Web API
سناریویی را فرض کنید که در آن برای انجام عملیات CRUD از یک سرویس Web API استفاده میشود. همچنین مدیریت دادهها با مدل Code-First پیاده سازی شده است. در مثال جاری یک کلاینت Console Application خواهیم داشت که یک سرویس Web API را فراخوانی میکند. توجه داشته باشید که هر اپلیکیشن در Solution مجزایی قرار دارد. تفکیک پروژهها برای شبیه سازی یک محیط n-Tier انجام شده است.
فرض کنید مدلی مانند تصویر زیر داریم.
همانطور که میبینید مدل جاری، سفارشات یک اپلیکیشن فرضی را معرفی میکند. میخواهیم مدل و کد دسترسی به دادهها را در یک سرویس Web API پیاده سازی کنیم، تا هر کلاینتی که از HTTP استفاده میکند بتواند عملیات CRUD را انجام دهد. برای ساختن سرویس مورد نظر مراحل زیر را دنبال کنید.
- در ویژوال استودیو پروژه جدیدی از نوع ASP.NET Web Application بسازید و قالب پروژه را Web API انتخاب کنید. نام پروژه را به Recipe1.Service تغییر دهید.
- کنترلر جدیدی از نوع WebApi Controller با نام OrderController به پروژه اضافه کنید.
- کلاس جدیدی با نام Order در پوشه مدلها ایجاد کنید و کد زیر را به آن اضافه نمایید.
public class Order { public int OrderId { get; set; } public string Product { get; set; } public int Quantity { get; set; } public string Status { get; set; } public byte[] TimeStamp { get; set; } }
- با استفاده از NuGet Package Manager کتابخانه Entity Framework 6 را به پروژه اضافه کنید.
- حال کلاسی با نام Recipe1Context ایجاد کنید و کد زیر را به آن اضافه نمایید.
public class Recipe1Context : DbContext { public Recipe1Context() : base("Recipe1ConnectionString") { } public DbSet<Order> Orders { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity<Order>().ToTable("Orders"); // Following configuration enables timestamp to be concurrency token modelBuilder.Entity<Order>().Property(x => x.TimeStamp) .IsConcurrencyToken() .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed); } }
- فایل Web.config پروژه را باز کنید و رشته اتصال زیر را به قسمت ConnectionStrings اضافه نمایید.
<connectionStrings> <add name="Recipe1ConnectionString" connectionString="Data Source=.; Initial Catalog=EFRecipes; Integrated Security=True; MultipleActiveResultSets=True" providerName="System.Data.SqlClient" /> </connectionStrings>
- فایل Global.asax را باز کنید و کد زیر را به آن اضافه نمایید. این کد بررسی Entity Framework Compatibility را غیرفعال میکند.
protected void Application_Start() { // Disable Entity Framework Model Compatibilty Database.SetInitializer<Recipe1Context>(null); ... }
- در آخر کد کنترلر Order را با لیست زیر جایگزین کنید.
public class OrderController : ApiController { // GET api/order public IEnumerable<Order> Get() { using (var context = new Recipe1Context()) { return context.Orders.ToList(); } } // GET api/order/5 public Order Get(int id) { using (var context = new Recipe1Context()) { return context.Orders.FirstOrDefault(x => x.OrderId == id); } } // POST api/order public HttpResponseMessage Post(Order order) { // Cleanup data from previous requests Cleanup(); using (var context = new Recipe1Context()) { context.Orders.Add(order); context.SaveChanges(); // create HttpResponseMessage to wrap result, assigning Http Status code of 201, // which informs client that resource created successfully var response = Request.CreateResponse(HttpStatusCode.Created, order); // add location of newly-created resource to response header response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = order.OrderId })); return response; } } // PUT api/order/5 public HttpResponseMessage Put(Order order) { using (var context = new Recipe1Context()) { context.Entry(order).State = EntityState.Modified; context.SaveChanges(); // return Http Status code of 200, informing client that resouce updated successfully return Request.CreateResponse(HttpStatusCode.OK, order); } } // DELETE api/order/5 public HttpResponseMessage Delete(int id) { using (var context = new Recipe1Context()) { var order = context.Orders.FirstOrDefault(x => x.OrderId == id); context.Orders.Remove(order); context.SaveChanges(); // Return Http Status code of 200, informing client that resouce removed successfully return Request.CreateResponse(HttpStatusCode.OK); } } private void Cleanup() { using (var context = new Recipe1Context()) { context.Database.ExecuteSqlCommand("delete from [orders]"); } } }
در قدم بعدی اپلیکیشن کلاینت را میسازیم که از سرویس Web API استفاده میکند.
- در ویژوال استودیو پروژه جدیدی از نوع Console Application بسازید و نام آن را به Recipe1.Client تغییر دهید.
- کلاس موجودیت Order را به پروژه اضافه کنید. همان کلاسی که در سرویس Web API ساختیم.
نکته: قسمت هایی از اپلیکیشن که باید در لایههای مختلف مورد استفاده قرار گیرند - مانند کلاسهای موجودیتها - بهتر است در لایه مجزایی قرار داده شده و به اشتراک گذاشته شوند. مثلا میتوانید پروژه ای از نوع Class Library بسازید و تمام موجودیتها را در آن تعریف کنید. سپس لایههای مختلف این پروژه را ارجاع خواهند کرد.
فایل program.cs را باز کنید و کد زیر را به آن اضافه نمایید.
private HttpClient _client; private Order _order; private static void Main() { Task t = Run(); t.Wait(); Console.WriteLine("\nPress <enter> to continue..."); Console.ReadLine(); } private static async Task Run() { // create instance of the program class var program = new Program(); program.ServiceSetup(); program.CreateOrder(); // do not proceed until order is added await program.PostOrderAsync(); program.ChangeOrder(); // do not proceed until order is changed await program.PutOrderAsync(); // do not proceed until order is removed await program.RemoveOrderAsync(); } private void ServiceSetup() { // map URL for Web API cal _client = new HttpClient { BaseAddress = new Uri("http://localhost:3237/") }; // add Accept Header to request Web API content // negotiation to return resource in JSON format _client.DefaultRequestHeaders.Accept. Add(new MediaTypeWithQualityHeaderValue("application/json")); } private void CreateOrder() { // Create new order _order = new Order { Product = "Camping Tent", Quantity = 3, Status = "Received" }; } private async Task PostOrderAsync() { // leverage Web API client side API to call service var response = await _client.PostAsJsonAsync("api/order", _order); Uri newOrderUri; if (response.IsSuccessStatusCode) { // Capture Uri of new resource newOrderUri = response.Headers.Location; // capture newly-created order returned from service, // which will now include the database-generated Id value _order = await response.Content.ReadAsAsync<Order>(); Console.WriteLine("Successfully created order. Here is URL to new resource: {0}", newOrderUri); } else Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase); } private void ChangeOrder() { // update order _order.Quantity = 10; } private async Task PutOrderAsync() { // construct call to generate HttpPut verb and dispatch // to corresponding Put method in the Web API Service var response = await _client.PutAsJsonAsync("api/order", _order); if (response.IsSuccessStatusCode) { // capture updated order returned from service, which will include new quanity _order = await response.Content.ReadAsAsync<Order>(); Console.WriteLine("Successfully updated order: {0}", response.StatusCode); } else Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase); } private async Task RemoveOrderAsync() { // remove order var uri = "api/order/" + _order.OrderId; var response = await _client.DeleteAsync(uri); if (response.IsSuccessStatusCode) Console.WriteLine("Sucessfully deleted order: {0}", response.StatusCode); else Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase); }
Successfully updated order: OK
Sucessfully deleted order: OK
شرح مثال جاری
با اجرای اپلیکیشن Web API شروع کنید. این اپلیکیشن یک کنترلر Web API دارد که پس از اجرا شما را به صفحه خانه هدایت میکند. در این مرحله اپلیکیشن در حال اجرا است و سرویسهای ما قابل دسترسی هستند.
حال اپلیکیشن کنسول را باز کنید. روی خط اول کد program.cs یک breakpoint تعریف کرده و اپلیکیشن را اجرا کنید. ابتدا آدرس سرویس Web API را پیکربندی کرده و خاصیت Accept Header را مقدار دهی میکنیم. با این کار از سرویس مورد نظر درخواست میکنیم که دادهها را با فرمت JSON بازگرداند. سپس یک آبجکت Order میسازیم و با فراخوانی متد PostAsJsonAsync آن را به سرویس ارسال میکنیم. این متد روی آبجکت HttpClient تعریف شده است. اگر به اکشن متد Post در کنترلر Order یک breakpoint اضافه کنید، خواهید دید که این متد سفارش جدید را بعنوان یک پارامتر دریافت میکند و آن را به لیست موجودیتها در Context جاری اضافه مینماید. این عمل باعث میشود که آبجکت جدید بعنوان Added علامت گذاری شود، در این مرحله Context جاری شروع به ردیابی تغییرات میکند. در آخر با فراخوانی متد SaveChanges دادهها را ذخیره میکنیم. در قدم بعدی کد وضعیت 201 (Created) و آدرس منبع جدید را در یک آبجکت HttpResponseMessage قرار میدهیم و به کلاینت ارسال میکنیم. هنگام استفاده از Web API باید اطمینان حاصل کنیم که کلاینتها درخواستهای ایجاد رکورد جدید را بصورت POST ارسال میکنند. درخواستهای HTTP Post بصورت خودکار به اکشن متد متناظر نگاشت میشوند.
در مرحله بعد عملیات بعدی را اجرا میکنیم، تعداد سفارش را تغییر میدهیم و موجودیت جاری را با فراخوانی متد PutAsJsonAsync به سرویس Web API ارسال میکنیم. اگر به اکشن متد Put در کنترلر سرویس یک breakpoint اضافه کنید، خواهید دید که آبجکت سفارش بصورت یک پارامتر دریافت میشود. سپس با فراخوانی متد Entry و پاس دادن موجودیت جاری بعنوان رفرنس، خاصیت State را به Modified تغییر میدهیم، که این کار موجودیت را به Context جاری میچسباند. حال فراخوانی متد SaveChanges یک اسکریپت بروز رسانی تولید خواهد کرد. در مثال جاری تمام فیلدهای آبجکت Order را بروز رسانی میکنیم. در شمارههای بعدی این سری از مقالات، خواهیم دید چگونه میتوان تنها فیلدهایی را بروز رسانی کرد که تغییر کرده اند. در آخر عملیات را با بازگرداندن کد وضعیت 200 (OK) به اتمام میرسانیم.
در مرحله بعد، عملیات نهایی را اجرا میکنیم که موجودیت Order را از منبع داده حذف میکند. برای اینکار شناسه (Id) رکورد مورد نظر را به آدرس سرویس اضافه میکنیم و متد DeleteAsync را فراخوانی میکنیم. در سرویس Web API رکورد مورد نظر را از دیتابیس دریافت کرده و متد Remove را روی Context جاری فراخوانی میکنیم. این کار موجودیت مورد نظر را بعنوان Deleted علامت گذاری میکند. فراخوانی متد SaveChanges یک اسکریپت Delete تولید خواهد کرد که نهایتا منجر به حذف شدن رکورد میشود.
در یک اپلیکیشن واقعی بهتر است کد دسترسی دادهها از سرویس Web API تفکیک شود و در لایه مجزایی قرار گیرد.
پیاده سازی RabbitMQ
- یک پروژه از نوع Asp.Net Core Web Application ایجاد میکنیم به نام RabbiMqExample.Producer که همان ارسال کننده (Producer) میباشد.
- یک پروژه از نوع Asp.Net Core Web Application به نام RabbitMqExample.Consumer برای دریافت کننده (Consumer).
- یک پروژه از نوع Class library .Net Core به نام RabbitMqExample.Common که شامل سرویسها و مدلهای مشترک بین Producer و Consumer میباشد.
public class RabbitMqConfiguration { public string HostName { get; set; } public string Username { get; set; } public string Password { get; set; } }
public interface IRabbitMqService { IConnection CreateChannel(); } public class RabbitMqService : IRabbitMqService { private readonly RabbitMqConfiguration _configuration; public RabbitMqService(IOptions<RabbitMqConfiguration> options) { _configuration = options.Value; } public IConnection CreateChannel() { ConnectionFactory connection = new ConnectionFactory() { UserName = _configuration.Username, Password = _configuration.Password, HostName = _configuration.HostName }; connection.DispatchConsumersAsync = true; var channel = connection.CreateConnection(); return channel; } }
public static class StartupExtension { public static void AddCommonService(this IServiceCollection services, IConfiguration configuration) { services.Configure<RabbitMqConfiguration>(a => configuration.GetSection(nameof(RabbitMqConfiguration)).Bind(a)); services.AddSingleton<IRabbitMqService, RabbitMqService>(); } }
<ItemGroup> <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" /> <PackageReference Include="RabbitMQ.Client" Version="6.2.1" /> </ItemGroup>
public interface IConsumerService { Task ReadMessgaes(); } public class ConsumerService : IConsumerService, IDisposable { private readonly IModel _model; private readonly IConnection _connection; public ConsumerService(IRabbitMqService rabbitMqService) { _connection = rabbitMqService.CreateChannel(); _model = _connection.CreateModel(); _model.QueueDeclare(_queueName, durable: true, exclusive: false, autoDelete: false); _model.ExchangeDeclare("UserExchange", ExchangeType.Fanout, durable: true, autoDelete: false); _model.QueueBind(_queueName, "UserExchange", string.Empty); } const string _queueName = "User"; public async Task ReadMessgaes() { var consumer = new AsyncEventingBasicConsumer(_model); consumer.Received += async (ch, ea) => { var body = ea.Body.ToArray(); var text = System.Text.Encoding.UTF8.GetString(body); Console.WriteLine(text); await Task.CompletedTask; _model.BasicAck(ea.DeliveryTag, false); }; _model.BasicConsume(_queueName, false, consumer); await Task.CompletedTask; } public void Dispose() { if (_model.IsOpen) _model.Close(); if (_connection.IsOpen) _connection.Close(); } }
- پارامتر اول، اسم queue میباشد
- پارامتر durable مشخص میکند که دادهها به صورت مانا باشند یا نه. اگر برابر true باشد، دیتاهای مربوط به queueها، در دیسک ذخیره میشوند؛ اما اگر برابر false باشد، بر روی حافظه ذخیره میشوند. در محیطهایی که مانایی اطلاعات مهم میباشد، باید مقدار این پارامتر را true کنید.
- پارامتر سوم: اطلاعات بیشتر
- پارامتر autoDelete اگر برابر true باشد، زمانی که تمامی Consumerها ارتباطشان با RabbitMq قطع شود، queue هم پاک میشود. اما اگر برابر true باشد، queue باقی میماند؛ حتی اگر هیچ Consumer ای به آن وصل نباشد.
- نام Exchange
- نوع Exchange که میتواند Headers , Topic , Fanout یا Direct باشد. اگر برابر Fanout باشد و اگر دادهای وارد Exchange شود، آنرا به تمامی queue هایی که به آن بایند شدهاست، ارسال میکند. اما اگر نوع آن Direct باشد، داده را به یک queue مشخص ارسال میکند؛ با استفاده از پارامتر routeKey.
- پارامترهای بعدی، durable و autoDelete هستند که همانند پارامترهای QueueDeclare عمل میکنند.
public class ConsumerHostedService : BackgroundService { private readonly IConsumerService _consumerService; public ConsumerHostedService(IConsumerService consumerService) { _consumerService = consumerService; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { await _consumerService.ReadMessgaes(); } }
public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; set; } public void ConfigureServices(IServiceCollection services) { services.AddCommonService(Configuration); services.AddSingleton<IConsumerService, ConsumerService>(); services.AddHostedService<ConsumerHostedService>(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { } }
[Route("api/[controller]/[action]")] [ApiController] public class RabbitController : ControllerBase { private readonly IRabbitMqService _rabbitMqService; public HomeController(IRabbitMqService rabbitMqService) { _rabbitMqService = rabbitMqService; } [HttpPost] public IActionResult SendMessage() { using var connection = _rabbitMqService.CreateChannel(); using var model = connection.CreateModel(); var body = Encoding.UTF8.GetBytes("Hi"); model.BasicPublish("UserExchange", string.Empty, basicProperties: null, body: body); return Ok(); } }
public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; set; } public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddCommonService(Configuration); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapDefaultControllerRoute(); }); } }
{ "RabbitMqConfiguration": { "HostName": "localhost", "Username": "guest", "Password": "guest" } }
version: "3.2" services: rabbitmq: image: rabbitmq:3-management-alpine container_name: 'rabbitmq' ports: - 5672:5672 - 15672:15672
Blazor 5x - قسمت 19 - کار با فرمها - بخش 7 - نکات ویژهی کار با EF-Core در برنامههای Blazor Server
مدیریت رجیستری در #C
ASP.NET MVC
- ASP.NET MVC #1
- ASP.NET MVC #2
- ASP.NET MVC #3
- ASP.NET MVC #4
- ASP.NET MVC #5
- ASP.NET MVC #6
- ASP.NET MVC #7
- ASP.NET MVC #8
- ASP.NET MVC #9
- ASP.NET MVC #10
- ASP.NET MVC #11
- ASP.NET MVC #12
- ASP.NET MVC #13
- ASP.NET MVC #14
- ASP.NET MVC #15
- ASP.NET MVC #16
- ASP.NET MVC #17
- ASP.NET MVC #18
- ASP.NET MVC #19
- ASP.NET MVC #20
- ASP.NET MVC #21
- ASP.NET MVC #22
- ASP.NET MVC #23
- ASP.NET MVC #24
- نحوه ارتقاء برنامههای موجود MVC3 به MVC4
- تغییرات بوجود آمده در Bundling and Minification -MVC4
- تغییرات بوجود آمده در Mobile Features-MVC4
- تغییرات بوجود آمده در Single Page Application (SPA)-MVC4
- تغییرات بوجود آمده در Razor -MVC4
- Globalization در ASP.NET MVC
- Globalization در ASP.NET MVC - قسمت دوم
- Globalization در ASP.NET MVC - قسمت سوم
- Globalization در ASP.NET MVC - قسمت چهارم
- Globalization در ASP.NET MVC - قسمت پنجم
- Globalization در ASP.NET MVC - قسمت ششم
- Globalization در ASP.NET MVC - قسمت هفتم
- بررسی تغییرات ASP.NET MVC 5 beta1
- مسیریابی (Routing) در ASP.NET MVC 5.x
- Attribute Routing در ASP.NET MVC 5
- قابلیت Attribute Routing در ASP.NET MVC 5
- یک تکنیک جالب در نحوه نام گذاری فیلدهای دیتابیس به منظور استفاده بهینه از فایلهای T4 در MVC 5
- نگاهی به هویت سنجی کاربران در ASP.NET MVC 5
- سفارشی کردن ASP.NET Identity در MVC 5
- افزودن تصدیق ایمیل به ASP.NET Identity در MVC 5
- ایجاد کپچایی (captcha) سریع و ساده در ASP.NET MVC 5
- توزیع یک اپلیکیشن ASP.NET MVC 5 روی Windows Azure
- معماری لایه بندی نرم افزار #1
- معماری لایه بندی نرم افزار #2
- معماری لایه بندی نرم افزار #3
- معماری لایه بندی نرم افزار #4
- CheckBoxList در ASP.NET MVC
- RadioButtonList در ASP.NET MVC
- مدیریت محل اعمال Google analytics در ASP.NET MVC
- استفاده از HttpGet در ASP.NET MVC، آری یا خیر؟!
- اثر وجود سشن بر پردازش موازی در ASP.NET
- استفاده از دکمههای CSS توئیتر در ASP.NET MVC
- نحوه صحیح تولید Url در ASP.NET MVC
- استفاده از OpenID در وب سایت جهت احراز هویت کاربران
- متدهای کمکی مفید در پروژههای asp.net mvc
- T4MVC : یکی از الزامات مدیریت پروژههای ASP.NET MVC
- مقدمه ای بر AutoMapper
- بهبود سرعت نمایش صفحات در ASP.NET MVC با حذف View Engines اضافی
- محدود کردن کاربرها به آپلود فایلهایی خاص در ASP.NET MVC
- ارسال فایل در ASP.NET MVC و اعتبار سنجی سمت کاربر
- فعال سازی قسمت ارسال فایل و تصویر ویرایشگر آنلاین RedActor در ASP.NET MVC
- معرفی پروژه Orchard
- مباحث تکمیلی مدلهای خود ارجاع دهنده در EF Code first
- سازگار کردن لینکهای قدیمی یک سایت با ساختار جدید آن در ASP.NET MVC
- CAPTCHAfa
- نکتهای در استفاده از AutoMapper
- یکپارچه سازی CKEditor با Lightbox
- تهیه خروجی RSS در برنامههای ASP.NET MVC
- ایجاد Helper سفارشی جهت نمایش ویدئو در ASP.NET MVC
- ساخت DropDownListهای مرتبط به کمک jQuery Ajax در MVC
- استفاده از دکمههای CSS توئیتر در ASP.NET MVC - قسمت دوم
- با ASP.MVC چه مزایایی را به دست خواهیم آورد
- نحوه اضافه کردن Auto-Complete به جستجوی لوسین در ASP.NET MVC و Web forms
- مقابله با پسوردهایی که ساده حدس زده میشوند
- غیرفعال کردن کش مرورگر در MVC
- Best Practice هایی برای ASP.NET MVC - قسمت اول
- چک لیست تهیه یک برنامه ASP.NET MVC
- استفاده از FluentValidation در ASP.NET MVC
- نحوه اجباری کردن استفاده از WWW در ASP.NET MVC
- نمایش رکوردها به ترتیب اولویت به کمک jQuery UI sortable در ASP.NET MVC
- کنترل عمومی فایلهای آپلودی در ASP.NET MVC
- هدایت خودکار کاربر به صفحه لاگین در حین اعمال Ajax ایی
- مدیریت سفارشی سطوح دسترسی کاربران در MVC
- بهبود SEO در ASP.NET MVC
- ایجاد قسمتهای Toggle در سایت با jQuery
- آشنایی و بررسی ابزار MiniProfiler
- استفاده از Flash Uploader در ASP.NET MVC
- استایل دهی به ستونهای header در WebGrid
- ELMAH و حملات XSS
- آموزش MEF#2(استفاده از MEF در Asp.Net MVC)
- نحوه استفاده از ViewModel در ASP.NET MVC
- مخفی کردن کوئری استرینگها در ASP.NET MVC توسط امکانات Routing
- توزیع پروژههای ASP.NET MVC بدون ارائه فایلهای View آن
- حذف هدرهای مربوط به وب سرور از طریق برنامه نویسی
- ایجاد helper برای Nivo Slider در Asp.net Mvc
- آشنایی با Fluent Html Helpers در MVC
- نحوه استفاده از افزونه Firebug برای دیباگ برنامههای ASP.NET مبتنی بر jQuery
- عدم امکان تغییر اطلاعات مدل در HTML Helpers پس از Postback در ASP.NET MVC
- اضافه کردن Watermark به تصاویر یک برنامه ASP.NET MVC در صورت لینک شدن در سایتی دیگر
- چگونگی رسیدگی به Null property در AutoMapper
- return File در ASP.NET MVC و نامهای یونیکد
- تولید SiteMap استاندارد و ایجاد یک ActionResult اختصاصی برای Return کردن SiteMap تولید شده
- نحوه ایجاد یک تصویر امنیتی (Captcha) با حروف فارسی در ASP.Net MVC
- الگوی PRG در ASP.NET MVC
- اعتبارسنجی سایتهای چند زبانه در ASP.NET MVC - قسمت اول
- آغاز به کار با Twitter Bootstrap در ASP.NET MVC
- استفاده از Twitter Bootstrap در کارهای روزمره طراحی وب
- نگاهی به اجزای تعاملی Twitter Bootstrap
- اعمال کلاسهای ویژه اعتبارسنجی Twitter bootstrap به فرمهای ASP.NET MVC
- ویرایش قالب پیش فرض Add View در ASP.NET MVC برای سازگار سازی آن با Twitter bootstrap
- استفاده از افزونه Typeahead مجموعه Twitter Bootstrap در ASP.NET MVC
- استفاده از modal dialogs مجموعه Twitter Bootstrap برای گرفتن تائید از کاربر
- Bundling and Minifying Inline Css and Js
- نمایش فرمهای مودال Ajax ایی در ASP.NET MVC به کمک Twitter Bootstrap
- MVC vs 3-Tier Pattern
- پلاگین جستجو با jquery و twitter bootstrap
- نمایش خطاهای اعتبارسنجی سمت کاربر ASP.NET MVC به شکل Tooltip به کمک Twitter bootstrap
- نمایش خطاهای اعتبارسنجی سمت کاربر ASP.NET MVC به شکل Popover به کمک Twitter bootstrap
- ساخت قالبهای نمایشی و ادیتور دکمه سه وضعیتی سازگار با Twitter bootstrap در ASP.NET MVC
- پیاده سازی Open Search در ASP.NET MVC
- Best Practice ی برای تأیید اعتبار کردن کاربران در ASP.NET MVC 4
- هدایت درخواست فایلهای استاتیک در ASP.NET MVC به یک کنترلر
- ModelBinder سفارشی در ASP.NET MVC
- ایجاد لینک با یک تصویر بوسیله Html Helper
- بارگزاری PartialView با استفاده از jQuery در زمان اجرا
- یافتن اکشن متدهای به اشتباه کش شده در ASP.NET MVC
- مروری مقدماتی بر ساخت برنامههای موبایل در MVC4
- اجرای برنامههای ASP.NET توسط Mono در Ubuntu
- اجرای برنامههای ASP.NET به کمک وب سرور Apache توسط Mono در Ubuntu
- فعالسازی استفاده از Session در ASP.NET MVC 4 API Controller ها
- ساخت منوهای چند سطحی در ASP.NET MVC
- طراحی ValidationAttribute دلخواه و هماهنگ سازی آن با ASP.NET MVC
- بهینه سازی برنامههای وب ASP.NET برای موتورهای جستجو (SEO)
- CheckBoxList برای فیلد Enum Flags مدل در ASP.Net MVC
- چطور مسیریابیهای ASP.NET MVC را دیباگ کنیم؟
- ذخیره TreeView ساخته شده توسط KendoUI در Asp.net MVC
- تنظیمات امنیتی Glimpse
- سفارشی سازی Binding یک خصوصیت از طریق Attributes
- Bundle کردن فایلهای LESS در MVC
- TwitterBootstrapMVC
- بررسی خطای Circular References در ASP.NET MVC Json Serialization
- ایجاد یک فیلتر سفارشی جهت تعیین Layout برای کنترلر و یا اکشن متد
- حذف فضاهای خالی در خروجی صفحات ASP.NET MVC
- جلوگیری از درج صفحات سایت در سایتی دیگر از طریق iframeها
- مشکل اعتبار سنجی jQuery validator در Bootstrap tabs
- افزودن هدرهای Content Security Policy به برنامههای ASP.NET
- امکان اعتبارسنجی با تاخیر در ASP.NET 4.5
- معرفی ASP.NET Identity
- متدهای احراز هویت در VS 2013
- توسعه اپلیکیشنهای ASP.NET با Windows Azure Active Directory
- ساخت یک اپلیکیشن ساده ToDo با ASP.NET Identity
- دریافت اطلاعات بیشتر از Social Providerها در VS 2013
- معرفی کتابخانه Postal برای ASP.NET MVC
- استفاده از Web Fonts در اپلیکیشنهای ASP.NET MVC
- استفاده از Awesomium.NET در برنامههای وب
- خواندن اطلاعات از سرور و نمایش آن توسط Angular در ASP.NET MVC
- آموزش Backload (آپلود چندین فایل به طور همزمان با آجاکس )
- یافتن اکشن متدهای Post ایی در ASP.NET MVC که فیلتر CSRF ندارند
- ایجاد سیستم وضعیت آب و هوا مانند گوگل (بخش اول)
- استفاده از #F در پروژههای MVC4
- توسعه کنترلر و مدل در F# MVC4
- تعامل با پایگاه داده با استفاده از EntityFramework در پروژههای F# MVC 4
- انجام کارهای زمانبندی شده در برنامههای ASP.NET توسط DNT Scheduler
- بررسی خروجی IsAjaxRequest در درخواستهای http$ توسط AngularJS
- بارگذاری فایلهای ایستا از پوشهی Views در ASP.NET MVC
- هدایت خودکار آدرسهای یافت نشد در یک سایت ASP.NET MVC به جستجوی سایت
- راههای متفاوت رندر لایهها در ASP.NET MVC
- پروژه Microsoft.AspNet.Mvc.Futures و تولید مسیرهای Strongly typed
- ASP.NET MVC و Identity 2.0 : مفاهیم پایه
- ارسال PingBack در ASP.NET
- Identity 2.0 : تایید حسابهای کاربری و احراز هویت دو مرحله ای
- مدیریت درخواستهای شرطی در ASP.NET MVC
- استفاده از Froala WYSIWYG Editor در ASP.NET
- استفاده از نگارش سوم Google Analytics API در سرویسهای ویندوز یا برنامههای وب
- بهینه سازی فایلهای js و css در برنامههای ASP.NET با استفاده از Combres - قسمت اول
- استفاده از pjax بجای ajax در ASP.NET MVC
- استفاده از افزونهی jsTree در ASP.NET MVC
- تفاوت ViewData و ViewBag و TempData و Session در MVC
- استفاده از چند فرم در کنار هم در ASP.NET MVC
- انجام کارهای پس زمینه در ASP.NET 4.5.2
- نمایش اخطارها و پیامهای بوت استرپ به کمک TempData در ASP.NET MVC
- صفحه بندی و مرتب سازی خودکار اطلاعات به کمک jqGrid در ASP.NET MVC
- فرمت کردن اطلاعات نمایش داده شده به کمک jqGrid در ASP.NET MVC
- فعال سازی و پردازش جستجوی پویای jqGrid در ASP.NET MVC
- استفاده از چند Routing در یک پروژه ASP.NET MVC بدون درد و خونریزی
- فعال سازی و پردازش صفحات پویای افزودن، ویرایش و حذف رکوردهای jqGrid در ASP.NET MVC
- رمزنگاری خودکار فیلدهای مخفی در ASP.NET MVC
- استفاده ازExpressionها جهت ایجاد Strongly typed view در ASP.NET MVC
- سفارشی سازی عناصر صفحات پویای افزودن و ویرایش رکوردهای jqGrid در ASP.NET MVC
- تهیه خروجی PDF و اکسل از حاصل جستجوی پویای jqGrid به کمک PDF Report
- Ajax.BeginForm و ارسال فایل به سرور در ASP.NET MVC
- آپلود فایل توسط فرمهای پویای jqGrid
- اختصاصی کردن Razor برای #C در MVC با استفاده از Extension Method
- روشی سریع برای ایجاد RSS و Sitemap در ASP.NET MVC
- اعتبارسنجی سفارشی سمت کاربر و سمت سرور در jqGrid
- OutputCache در ASP.NET MVC
- فعال سازی و پردازش Inline Add در jqGrid
- بهینه سازی سرعت یافت ویوها با سفارشی سازی Lookup Caching در Razor View Engine
- گروه بندی اطلاعات در jqGrid
- نمایش Subgrid در jqGrid
- ایجاد زیر گریدهای چند سطحی در jqGrid
- نمایش ساختارهای درختی توسط jqGrid
- سازگارسازی کلاسهای اعتبارسنجی Twitter Bootstrap 3 با فرمهای ASP.NET MVC
- اعتبارسنجی در فرمهای ASP.NET MVC با Remote Validation
- قالبهای سفارشی برای HtmlHelperها
- ارسال ویدیو بصورت Async توسط Web Api
- اعتبار سنجی سمت کاربر wysiwyg-editorها در ASP.NET MVC
- بررسی مقدمات کتابخانهی JSON.NET
- تنظیمات و نکات کاربردی کتابخانهی JSON.NET
- استفاده از JSON.NET در ASP.NET MVC
- LINQ to JSON به کمک JSON.NET
- آشنایی با چالشهای امنیتی در توسعه برنامههای تحت وب، بخش اول
- نمایش بلادرنگ اعلامی به تمام کاربران در هنگام درج یک رکورد جدید
- پیاده سازی Template تو در تو در AngularJS و ASP.NET MVC
- یکپارچه سازی سیستم اعتبارسنجی ASP.NET MVC با Kendo UI validator
- ساخت یک Form Generator ساده در MVC
- آشنایی با WebDav و نحوه استفاده از آن
- قابلیت Templated Razor Delegate
- اعمال تزریق وابستگیها به مثال رسمی ASP.NET Identity
- ثبت جزئیات استثناهای Entity framework توسط ELMAH
- نمایش بلادرنگ اعلامی به تمام کاربران در هنگام درج یک رکورد جدید به صورت notification
- کار با وب سرویس جاوایی تشخیص ایمیلهای موقتی در دات نت
- فراخوانی متدهای Controllerها در Viewهای ASP.NET MVC
- لغو اجرای یک اکشن فیلتر برای یک اکشن خاص در MVC
- کار با اسکنر در برنامههای تحت وب (قسمت اول)
- کار با اسکنر در برنامههای تحت وب (قسمت دوم و آخر)
- تبدیل یک View به رشته و بازگشت آن به همراه نتایج JSON حاصل از یک عملیات Ajax ایی در ASP.NET MVC
- آشنایی با ساختار ViewBag
- مدیریت سشنها در برنامههای وب به کمک تزریق وابستگیها
- خلاصهای از روشهای ارسال دادههای سمت سرور به کدهای جاوا اسکریپتی در ASP.NET MVC
- یکدست کردن "ی" و "ک" در ASP.NET MVC با پیادهسازی یک Model Binder
- حذف پردازش درخواستهای فایلهای استاتیک در متد Application_AuthenticateRequest
- دریافت خطاهای موجود در Viewهای ASP.NET MVC در زمان کامپایل
- پیاده سازی یک متد الحاقی برای تبدیل آدرس فیزیکی به آدرس مجازی (آدرس سرور)
- استفاده از Razor در فایلهای JavaScript و CSS
- عمومی سازی الگوریتمها با استفاده از Reflection
طراحی یک معماری خوب و مناسب یکی از عوامل مهم تولید یک برنامه
کاربردی موفق میباشد. بنابراین انتخاب یک ساختار مناسب به منظور تولید برنامه
کاربردی بسیار مهم و تا حدودی نیز سخت است. در اینجا یاد خواهیم گرفت که چگونه یک
طراحی مناسب را انتخاب نماییم. همچنین روشهای مختلف تولید برنامههای کاربردی را
که مطمئنا شما هم از برخی از این روشها استفاده نمودید را بررسی مینماییم و مزایا
و معایب آن را نیز به چالش میکشیم.
ضد الگو (Antipattern) – رابط کاربری هوشمند (Smart UI)
با استفاده از Visual Studio یا به اختصار VS، میتوانید برنامههای کاربردی را به راحتی تولید نمایید. طراحی رابط کاربری به آسانی عمل کشیدن و رها کردن (Drag & Drop) کنترلها بر روی رابط کاربری قابل انجام است. همچنین در پشت رابط کاربری (Code Behind) تمامی عملیات مربوط به مدیریت رویدادها، دسترسی به داده ها، منطق تجاری و سایر نیازهای برنامه کاربردی، کد نویسی خواهند شد. مشکل این نوع کدنویسی بدین شرح است که تمامی نیازهای برنامه در پشت رابط کاربری قرار میگیرند و موجب تولید کدهای تکراری، غیر قابل تست، پیچیدگی کدنویسی و کاهش قابلیت استفاده مجدد از کد میگردد.
به این روش کد نویسی Smart UI میگویند که موجب تسهیل تولید برنامههای کاربردی میگردد. اما یکی از مشکلات عمدهی این روش، کاهش قابلیت نگهداری و پشتیبانی و عمر کوتاه برنامههای کاربردی میباشد که در برنامههای بزرگ به خوبی این مشکلات را حس خواهید کرد.
از آنجایی که تمامی برنامه نویسان مبتدی و تازه کار، از جمله من و شما در روزهای اول برنامه نویسی، به همین روش کدنویسی میکردیم، لزومی به ارائه مثال در رابطه با این نوع کدنویسی نمیبینم.
تفکیک و جدا سازی اجزای برنامه کاربردی (Separating Your Concern)
راه حل رفع مشکل Smart UI، لایه بندی یا تفکیک اجزای برنامه از یکدیگر میباشد. لایه بندی برنامه میتواند به شکلهای مختلفی صورت بگیرد. این کار میتواند توسط تفکیک کدها از طریق فضای نام (Namespace)، پوشه بندی فایلهای حاوی کد و یا جداسازی کدها در پروژههای متفاوت انجام شود. در شکل زیر نمونه ای از معماری لایه بندی را برای یک برنامه کاربردی بزرگ میبینید.
به منظور پیاده سازی یک برنامه کاربردی لایه بندی شده و تفکیک اجزای برنامه از یکدیگر، مثالی را پیاده سازی خواهیم کرد. ممکن است در این مثال با مسائل جدید و شیوههای پیاده سازی جدیدی مواجه شوید که این نوع پیاده سازی برای شما قابل درک نباشد. اگر کمی صبر پیشه نمایید و این مجموعهی آموزشی را پیگیری کنید، تمامی مسائل نامانوس با جزئیات بیان خواهند شد و درک آن برای شما ساده خواهد گشت. قبل از شروع این موضوع را هم به عرض برسانم که علت اصلی این نوع پیاده سازی، انعطاف پذیری بالای برنامه کاربردی، پشتیبانی و نگهداری آسان، قابلیت تست پذیری با استفاده از ابزارهای تست، پیاده سازی پروژه بصورت تیمی و تقسیم بخشهای مختلف برنامه بین اعضای تیم و سایر مزایای فوق العاده آن میباشد.
1- Visual Studio را باز کنید و یک Solution خالی با نام SoCPatterns.Layered ایجاد نمایید.
· جهت ایجاد Solution خالی، پس از انتخاب New Project، از سمت چپ گزینه Other Project Types و سپس Visual Studio Solutions را انتخاب نمایید. از سمت راست گزینه Blank Solution را انتخاب کنید.
2- بر روی Solution کلیک راست نموده و از گزینه Add > New Project یک پروژه Class Library با نام SoCPatterns.Layered.Repository ایجاد کنید.
3- با استفاده از روش فوق سه پروژه Class Library دیگر با نامهای زیر را به Solution اضافه کنید:
- SoCPatterns.Layered.Model
- SoCPatterns.Layered.Service
- SoCPatterns.Layered.Presentation
4- با توجه به نیاز خود یک پروژه دیگر را باید به Solution اضافه نمایید. نوع و نام پروژه در زیر لیست شده است که شما باید با توجه به نیاز خود یکی از پروژههای موجود در لیست را به Solution اضافه کنید.
- Windows Forms Application (SoCPatterns.Layered.WinUI)
- WPF Application (SoCPatterns.Layered.WpfUI)
- ASP.NET Empty Web
Application (SoCPatterns.Layered.WebUI)
- ASP.NET MVC 4 Web
Application (SoCPatterns.Layered.MvcUI)
5- بر روی پروژه SoCPatterns.Layered.Repository کلیک راست نمایید و با انتخاب گزینه Add Reference به پروژهی SoCPatterns.Layered.Model ارجاع دهید.
6- بر روی پروژه SoCPatterns.Layered.Service کلیک راست نمایید و با انتخاب گزینه Add Reference به پروژههای SoCPatterns.Layered.Model و SoCPatterns.Layered.Repository ارجاع دهید.
7- بر روی پروژه SoCPatterns.Layered.Presentation کلیک راست نمایید و با انتخاب گزینه Add Reference به پروژههای SoCPatterns.Layered.Model و SoCPatterns.Layered.Service ارجاع دهید.
8- بر روی پروژهی UI خود به عنوان مثال SoCPatterns.Layered.WebUI کلیک راست نمایید و با انتخاب گزینه Add Reference به پروژههای SoCPatterns.Layered.Model، SoCPatterns.Layered.Repository، SoCPatterns.Layered.Service و SoCPatterns.Layered.Presentation ارجاع دهید.
9- بر روی پروژهی UI خود به عنوان مثال SoCPatterns.Layered.WebUI کلیک راست نمایید و با انتخاب گزینه Set as StartUp Project پروژهی اجرایی را مشخص کنید.
10- بر روی Solution کلیک راست نمایید و با انتخاب گزینه Add > New Solution Folder پوشههای زیر را اضافه نموده و پروژههای مرتبط را با عمل Drag & Drop در داخل پوشهی مورد نظر قرار دهید.
- 1. UI
- § SoCPatterns.Layered.WebUI
- 2. Presentation Layer
- § SoCPatterns.Layered.Presentation
- 3. Service Layer
- § SoCPatterns.Layered.Service
- 4. Domain Layer
- § SoCPatterns.Layered.Model
- 5. Data Layer
- § SoCPatterns.Layered.Repository
- توجه
داشته باشید که پوشه بندی برای مرتب سازی لایهها و دسترسی راحتتر به آنها میباشد.
پیاده سازی ساختار لایه بندی برنامه به صورت کامل انجام شد. حال به پیاده سازی کدهای مربوط به هر یک از لایهها و بخشها میپردازیم و از لایه Domain شروع خواهیم کرد.