این سری از مقالات به ساخت یک سیستم نظرسنجی آنلاین با به روزرسانی های بلادرنگ با استفاده از SignalR 2، jQuery، EF Core، Core MVC و۲ Web API می پردازد.
با ساخت یک اپلیکیشن از صفر تا صد، نگاهی می اندازیم به این که هر یک از این تکنولوژی ها چگونه در ASP.NET Core 1.0 استفاده می شوند.

نظرسنجی آنلاین

در این سری به خصوص، ما اساس هسته یک اپلیکیشن را با شروع از ساخت یک دیتابیس جدید، ایجاد یک پروژه جدید ASP.NET Core، و تنظیمات دسترسی به داده ها با استفاده از EF core می سازیم.

همچنین یک صفحه ساده برای اضافه کردن یک رای جدید می سازیم و با استفاده از ASP.NET SignalR 2 یک صفحه برای نمایش رای های اضافه شده ی اخیر به صورت بلادرنگ ایجاد می کنیم.

چه مطالبی را خواهیم آموخت

  •  ایجاد یک دیتابیس با استفاده از SQL Server 2014
  •  ایجاد یک پروژه ASP.NET Core Project
  •  یکپارچه سازی Entity Framework Core 1.0
  •  ایجاد مدل های Entity از دیتابیس موجود (مهندسی معکوس)
  •  ثبت DBContext با استفاده از Dependency Injection
  •  ایجاد یک صفحه مدیریت رای با استفاده از Core MVC
    • اضافه کردن ViewModels
    • اضافه کردن PollManager Repository
    • ثبت PollManager Repository
    • اضافه کردن یک Controller
    • اضافه کردن یک View
    • فعال سازی MVC و Developer Diagnostics
    • اجرای برنامه
    • ادغام ASP.NET SignalR 2
  • ادغام پکیج های سمت کلاینت – jQuery و اسکریپت های SignalR
  •  ایجاد یک میان افزار برای نگاشت SignalR
  •  اضافه کردن SignalR به روند توسعه
  •  ایجاد یک Hub
  •  فراخوانی متد Hub
  •  ایجاد یک Web API
  •  نمایش رای

ایجاد دیتابیس

MS SQL Server Management Studio را باز کرده و اسکریپت SQL زیر را برای ایجاد دیتابیس و جدول ها اجرا می کنیم.

CREATE DATABASE ASPNETCoreDemoDB  
GO  
  
USE [ASPNETCoreDemoDB]  
GO  
  
  
CREATE TABLE [dbo].[Poll](  
    [PollID] [int] IDENTITY(1,1) NOT NULL,  
    [Question] [nvarchar](300) NOT NULL,  
    [Active] [bit] NOT NULL,  
 CONSTRAINT [PK_Poll] PRIMARY KEY CLUSTERED   
(  
    [PollID] ASC  
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]  
) ON [PRIMARY]  
  
GO  
  
CREATE TABLE [dbo].[PollOption](  
    [PollOptionID] [int] IDENTITY(1,1) NOT NULL,  
    [PollID] [int] NOT NULL,  
    [Answers] [nvarchar](200) NOT NULL,  
    [Vote] [int] NOT NULL,  
 CONSTRAINT [PK_PollOption] PRIMARY KEY CLUSTERED   
(  
    [PollOptionID] ASC  
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]  
) ON [PRIMARY]  
  
GO  
  
ALTER TABLE [dbo].[PollOption]  WITH CHECK ADD  CONSTRAINT [FK_PollOption_PollOption] FOREIGN KEY([PollID])  
REFERENCES [dbo].[Poll] ([PollID])  
GO  
  
ALTER TABLE [dbo].[PollOption] CHECK CONSTRAINT [FK_PollOption_PollOption]  
GO  

اسکریپت SQL بالا باید دیتابیس ASPNETCoreDemoDB با جدول های زیر را ایجاد نماید.

نظرسنجی آنلاین

ایجاد یک پروژه ASP.NET Core

مرحله بعدی ما ساخت نظرسنجی آنلاین یک صفحه مدیریت نظرسنجی است که می توانیم نظرات خود را برای دسترسی کاربران اضافه کنیم تا رای خود را بدهند.ویژوال استودیو ۲۰۱۵ را باز کرده و یک پروژه جدید ASP.NET Core Web Application درست مانند شکل زیر ایجاد می کنیم:

نظرسنجی آنلاین

نام دلخواه خود را به پروژه نظرسنجی آنلاین می دهیم، در این مثال ما آن را “ASPNETCoreSignalRDemo” انتخاب کردیم. روی OK کلیک کرده و سپس همانطور که در شکل زیر نشان داده شده “Web API” را در قالب های ASP.NET Core انتخاب می کنیم:

نظرسنجی آنلاین

حالا فقط روی OK کلیک می کنیم تا ویژوال استودیو فایل های موردنیاز ما برای اجرا را تولید کند.سپس فولدر “Models” را در ریشه اپلیکیشن می سازیم و در زیرشاخه آن، فولدر “DB” و “ViewModels” را اضافه می کنیم. solution ما درحال حاضر به این شکل درمی آید:

نظرسنجی آنلاین

فولدر “DB” شامل دسترسی داده های ما خواهد بود. در این مثال، ما قصد داریم از Entity Framework Core 1.0 به عنوان مکانیزم Data Access استفاده نماییم. این به معنی است که ما از EF Designer برای تولید مدل ها استفاده نخواهیم کرد چرا که EF Designer (EDMX) در ASP.NET Core 1.0 پشتیبانی نمی شود.

نظرسنجی آنلاین

فولدر “ViewModels” شامل یک مجموعه از مدل هایی است که قرار است در View استفاده شوند. این مدل ها فقط کلاس هایی هستند که برخی propertyها را در خود جای می دهند که ما فقط برای View خود نیاز داریم، بنابراین انتقال داده ها را بسیار سبک تر می کنند.

یکپارچه سازی Entity Framework Core 1.0

ASP.NET Core طراحی شد که کم حجم، ماژولار و قابل اتصال باشد. این امکان را به ما می دهد که کامپوننت هایی را وصل کنیم که فقط برای پروژه ما موردنیاز هستند.

به عبارت دیگر، ما باید پکیج Entity Framework Core را به اپلیکیشن ASP.NET Core خود اضافه کنیم چون ما به آن نیاز خواهیم داشت.

برای جزئیات بیشتر درباره EF Core می توانید بلاگ زیر را مطالعه نمایید: انتشار Entity Framework 1.0

برای اضافه کردن پکیج ها در ASP.NET Core دو روش وجود دارد. هم می توانیم از فایل “project.json” به منظور بهره بردن از ویژگی intellisense استفاده کنیم، یا از طریق NuGet Package Manager این کار را انجام دهیم.

در این مثال، ما می خواهیم از NPM استفاده کنیم بنابراین می توانیم یک رفرنس بصری داشته باشیم.

حالا روی ریشه اپلیکیشن راست کلیک کرده و Manage NuGet Packages را انتخاب می کنیم. در کادر جستجو عبارت “Microsoft.EntityFrameworkCore.SqlServer” را تایپ می نماییم. نتیجه چیزی شبیه به تصویر زیر خواهد بود.

نظرسنجی آنلاین

“Microsoft.EntityFrameworkCore.SqlServer” را انتخاب کرده و روی Install کلیک می کنیم. به همین صورت دستورالعمل wizard را دنبال می کنیم تا نصب آن به اتمام برسد.
می خواهیم از Database-Approach برای کار با دیتابیس موجود استفاده کنیم و برای این کار باید پکیج های زیر را نصب نماییم:

  •  Microsoft.EntityFrameworkCore.Tools(v1.0.0-preview2-final)
  •  Microsoft.EntityFrameworkCore.SqlServer.Design(v1.0.0)

حالا ادامه داده و آن ها را از طریق NPM، همانطور که در شکل زیر نشان داده شده است نصب می کنیم.

نظرسنجی آنلاین

نظرسنجی آنلاین

زمانی که بازیابی این پکیج ها به اتمام رسید، باید آن ها را در رفرنس های پروژه به شکل زیر مشاهده نماییم.

نظرسنجی آنلاین

حالا فایل project.json خود را باز کرده و آیتم Microsoft.EntityFrameworkCore.Tools در زیر بخش tools اضافه می نماییم.


"tools": {  
"Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final",  
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"  
},  

 

ساخت مدل های Entity از دیتابیس موجود

حالا وقت آن است که مدل های EF را براساس دیتابیس موجودی که قبل تر ایجاد کردیم، بسازیم. برای تولید مدل ها از دیتابیس موجود دو روش وجود دارد:

روش ۱: استفاده از Package Manager Console

 به منوی Tools -> NuGet Package Manager -> Package Manager Console می رویم.
و سپس دستور زیر را برای ایجاد مدل از دیتابیس موجود اجرا می کنیم.

Scaffold-DbContext “Server=WIN-EHM93AP21CF\SQLEXPRESS;Database=ASPNETCoreDemoDB;Trusted_Connection=True;” Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models/DB

روش ۲: استفاده از Command Window

به فولدر ریشه اپلیکیشن جایی که project.json قرار دارد، می رویم. در این مورد “ASPNETCoreSignalRDemo”
با گرفتن دکمه Shift و سپس راست کلیک کردن گزینه “Open command window here” را انتخاب می نماییم.
سپس اسکریپت زیر را اجرا می کنیم.

dotnet ef dbcontext scaffold “Server=WIN-EHM93AP21CF\SQLEXPRESS;Database=ASPNETCoreDemoDB;Integrated Security=True;” Microsoft.EntityFrameworkCore.SqlServer –output-dir Models/DB

این دستور مدل ها را از دیتابیس درون فولدر Models/DB تولید می کند. تصویر زیر آن را نشان می دهد:

نظرسنجی آنلاین

نکات

  •  اگر هنوز خطایی دریافت می کنید، بنابراین ممکن است شما نیاز به آپدیت کردن PowerSell به ورژن ۵ دارید. می توانید آن را از اینجا دانلود نمایید.
  •  لازم است که مقدار Server و Database را براساس پیکربندی سرور در connection string تغییر دهید.

کد تولیدشده به شکل زیر است:

کلاس ASPNETCoreDemoDBContext

using System;  
using Microsoft.EntityFrameworkCore;  
using Microsoft.EntityFrameworkCore.Metadata;  
  
namespace ASPNETCoreSignalRDemo.Models.DB  
{  
    public partial class ASPNETCoreDemoDBContext : DbContext  
    {  
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)  
        {  
          optionsBuilder.UseSqlServer(@"Server=WIN-EHM93AP21CF\SQLEXPRESS;Database=ASPNETCoreDemoDB;Integrated Security=True;");  
        }  
  
        protected override void OnModelCreating(ModelBuilder modelBuilder)  
        {  
            modelBuilder.Entity<Poll>(entity =>  
            {  
                entity.Property(e => e.PollId).HasColumnName("PollID");  
  
                entity.Property(e => e.Question).HasMaxLength(300);  
            });  
  
            modelBuilder.Entity<PollOption>(entity =>  
            {  
                entity.Property(e => e.PollOptionId).HasColumnName("PollOptionID");  
  
                entity.Property(e => e.Answers)  
                    .IsRequired()  
                    .HasMaxLength(200);  
  
                entity.Property(e => e.PollId).HasColumnName("PollID");  
  
                entity.HasOne(d => d.Poll)  
                    .WithMany(p => p.PollOption)  
                    .HasForeignKey(d => d.PollId)  
                    .OnDelete(DeleteBehavior.Restrict)  
                    .HasConstraintName("FK_PollOption_PollOption");  
            });  
        }  
        public virtual DbSet<Poll> Poll { get; set; }  
        public virtual DbSet<PollOption> PollOption { get; set; }  
    }  
} 

کلاس Poll

using System.Collections.Generic;  
  
namespace ASPNETCoreSignalRDemo.Models.DB  
{  
    public partial class Poll  
    {  
        public Poll()  
        {  
            PollOption = new HashSet<PollOption>();  
        }  
  
        public int PollId { get; set; }  
        public string Question { get; set; }  
        public bool Active { get; set; }  
  
        public virtual ICollection<PollOption> PollOption { get; set; }  
    }  
}  

کلاس PollOption


using System;  
  
namespace ASPNETCoreSignalRDemo.Models.DB  
{  
    public partial class PollOption  
    {  
        public int PollOptionId { get; set; }  
        public int PollId { get; set; }  
        public string Answers { get; set; }  
        public int Vote { get; set; }  
  
        public virtual Poll Poll { get; set; }  
    }  
}  

اگر توجه داشته باشید، مدل های تولید شده به صورت کلاس های جزئی (Partial class) هستند. به این معنی که می توانیم هر زمان که نیاز داشتیم آن ها را با ساختن کلاس جزئی دیگری برای هر یک از کلاس های entity/model توسعه دهیم.

ثبت DBContext با استفاده از Dependency Injection

مرحله بعدی ثبت ASPNETCoreDemoDBContext با استفاده از Dependency Injection می باشد. برای پیروی کردن از الگوی پیکربندی ASP.NET Core، پیکربندی فراهم کننده دیتابیس را به کلاس Startup.cs انتقال می دهیم. برای این کار، فقط مراحل زیر را دنبال می کنیم.

  •  Models\DB\ASPNETCoreDemoDBContext را باز می کنیم.
  •  متد OnConfiguring() را پاک کرده و کد زیر را اضافه می کنیم.

public ASPNETCoreDemoDBContext(DbContextOptions<ASPNETCoreDemoDBContext> options)  
: base(options)  
{ }  

• فایل appsetting.json را باز کرده و اسکریپت زیر را برای connection string دیتابیس خود اضافه می کنیم.


"ConnectionStrings": {  
"PollSystemDatabase": "Server=WIN-EHM93AP21CF\\SQLEXPRESS;Database=ASPNETCoreDemoDB;Integrated Security=True;"  
}  
  •  فایل Startup.cs را باز می کنیم.
  •  عبارات using زیر را اضافه می نماییم.
using ASPNETCoreSignalRDemo.Models;  
using ASPNETCoreSignalRDemo.Models.DB;  
using Microsoft.EntityFrameworkCore;  
  • خط کدهای زیر را درون متد ConfigureService() اضافه می نماییم.
public void ConfigureServices(IServiceCollection services)  
{  
// Add ASPNETCoreDemoDBContext services.  
services.AddDbContext<ASPNETCoreDemoDBContext>(options => options.UseSqlServer(Configuration.GetConnectionString("PollSystemDatabase")));   
// Add MVC services.  
services.AddMvc();  
}  

به این ترتیب، ما آماده کار با داده ها هستیم. مرحله بعدی مرحله ساخت اپلیکیشن است.

ایجاد صفحه مدیریت نظرسنجی آنلاین

اولین کاری که ما می خواهیم انجام دهیم ساخت صفحه مدیریت نظرسنجی آنلاین است. در این صفحه فرمی می سازیم که به ما امکان ثبت یک نظر جدید در دیتابیس با استفاده از MVC را می دهد.

اضافه کردن ViewModels

حالا اجازه دهید “AddPollViewModel” را بسازیم. کلاس زیر را در زیر فولدر ViewModels می سازیم.

using System.ComponentModel.DataAnnotations;  
  
namespace ASPNETCoreSignalRDemo.Models.ViewModels  
{  
    public class AddPollViewModel  
    {  
        [Required(ErrorMessage = "Question is required.")]     
        public string Question { get; set; }  
        [Required(ErrorMessage = "Answer is required.")]  
        public string Answer { get; set; }      
    }  
}  

کلاس بالا شامل دو property است که با استفاده از Data Annotation با صفات Required طراحی شده است تا قوانین از پیش تعریف شده اعتبارسنجی را اعمال نمایند.

کلاس دیگری در فولدر ViewModels ایجاد کرده و نام آن را “PollDetailsViewModel” می گذاریم. کد زیر مربوط به کلاس PollDetailsViewModel می باشد:

using System.Collections.Generic;  
  
namespace ASPNETCoreSignalRDemo.Models.ViewModels  
{  
    public class PollDetailsViewModel  
    {  
        public int PollID { get; set; }  
        public string Question { get; set; }  
        public IEnumerable<DB.PollOption> PollOption { get; set; }  
    }  
} 

اضافه کردن PollManager Repository

یک کلاس/اینترفیس جدید زیر فولدر Models ایجاد کرده و نام آن را “IPollManager” می گذاریم. کد درون آن فایل را به روزرسانی کرده و کد آن به شکل زیر درمی آید:

using System.Collections.Generic;  
using ASPNETCoreSignalRDemo.Models.ViewModels;  
  
namespace ASPNETCoreSignalRDemo.Models  
{  
    public interface IPollManager  
    {  
        bool AddPoll(AddPollViewModel pollModel);  
        IEnumerable<PollDetailsViewModel> GetActivePoll();  
    }  
}  

اگر توجه کنید در این آموزش نظرسنجی آنلاین، ما داریم به جای یک کلاس، یک اینترفیس تعریف می کنیم. این اینترفیس در Controller تزریق خواهد شد بنابراین ما فقط نیاز داریم که با اینترفیس صحبت کنیم به جای اینکه پیاده سازی واقعی از repository داشته باشیم.

سپس می خواهیم کلاسی بسازیم که اینترفیس IPollManager را پیاده سازی کند. روی فولدر Models راست کلیک می کنیم و یک کلاس جدید ایجاد می کنیم. نام آن را “PollManager” می گذاریم و سپس کد زیر را در آن می نویسیم:

 

using System;  
using System.Collections.Generic;  
using System.Linq;  
using ASPNETCoreSignalRDemo.Models.DB;  
using ASPNETCoreSignalRDemo.Models.ViewModels;  
using Microsoft.EntityFrameworkCore;  
  
namespace ASPNETCoreSignalRDemo.Models  
{  
    public class PollManager : IPollManager  
    {  
        private readonly ASPNETCoreDemoDBContext _db;  
        public PollManager(ASPNETCoreDemoDBContext context)  
        {  
            _db = context;  
        }  
  
        public IEnumerable<PollDetailsViewModel> GetActivePoll()  
        {  
            if (_db.Poll.Any())  
                return _db.Poll.Include(o => o.PollOption).Where(o => o.Active == true)  
                    .Select(o => new PollDetailsViewModel {  
                        PollID = o.PollId,  
                        Question = o.Question,  
                        PollOption = o.PollOption  
                    });  
  
            return Enumerable.Empty<PollDetailsViewModel>();  
        }  
  
        public bool AddPoll(AddPollViewModel pollModel)  
        {  
             
            using (var dbContextTransaction = _db.Database.BeginTransaction())  
            {  
                try  
                {  
                    var answers = pollModel.Answer.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);  
                    Poll poll = new Poll();  
                    poll.Question = pollModel.Question;  
                    poll.Active = true;  
                    _db.Poll.Add(poll);  
                    _db.SaveChanges();  
  
                    foreach (var answer in answers)  
                    {  
                        PollOption option = new PollOption();  
                        option.PollId = poll.PollId;  
                        option.Answers = answer;  
                        option.Vote = 0;  
                        _db.PollOption.Add(option);  
                        _db.SaveChanges();  
                    }  
  
                    dbContextTransaction.Commit();  
  
                }  
                catch  
                {  
                    //TO DO: log error here  
                    dbContextTransaction.Rollback();  
                }  
            }  
  
            return true;  
        }  
    }  
}  

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

در حال حاضر، کلاس PollManager شامل دو متد است. متد GetActivePoll() با استفاده از LINQ نظرسنجی فعال را از دیتابیس دریافت می کند و Ienumerableای از PollDetailsViewModel برمی گرداند.

متد AddPoll() داده های یک نظر جدید را به دیتابیس اضافه می کند. کاری که می کند این است که یک رکورد جدید به جدول Poll اضافه کرده و سپس رکوردهای مربوط به جدول PollOption را از طریق زدن حلقه تکرار روی پاسخ ها اضافه می نماید.

اگر توجه کنید، ما از یک تراکنش ساده درون متد استفاده کردیم. به این دلیل که جدول PollOption به جدول Poll مرتبط است و ما باید مطمئن شویم که فقط درصورتی که عملیات برای هر جدول موفقیت آمیز باشد، تغییرات را به دیتابیس اعمال (commit) می کنیم.

Database.BeginTransaction() فقط در EF 6 و نسخه های بعدی آن موجود است.

ثبت PollManager Repository

حالا خط زیر را درون متد Configure در فایل Startup.cs وارد می کنیم:

services.AddScoped<IPollManager, PollManager>();  

ما باید IPollManager را در service container ثبت کنیم چرا که کلاس PollManager شی ای از ASPNETCoreDemoDBContext را در سازنده خود درخواست می کند. Container مسئول حل و فصل همه وابستگی ها در نمودار بوده و سرویس کاملا حل شده را برمی گرداند.

اضافه کردن یک کنترلر

روی فولدر Controllers راست کلیک کرده و سپس Add>New Item>MVC Controller Class را انتخاب می کنیم. نام آن را “HomeController” گذاشته و کد درون کلاس را به شکل زیر به روزرسانی می کنیم:

using Microsoft.AspNetCore.Mvc;  
using ASPNETCoreSignalRDemo.Models;  
using ASPNETCoreSignalRDemo.Models.ViewModels;  
  
namespace ASPNETCoreSignalRDemo.Controllers  
{  
    public class HomeController : Controller  
    {  
        private readonly IPollManager _pollManager;  
  
        public HomeController(IPollManager pollManager)  
        {  
            _pollManager = pollManager;  
        }  
  
        public IActionResult Index()  
        {  
            return View();  
        }  
  
        public IActionResult AddPoll()  
        {  
            return View();  
        }  
  
        [HttpPost]  
        [ValidateAntiForgeryToken]  
        public IActionResult AddPoll(AddPollViewModel poll)  
        {  
            if (ModelState.IsValid) {  
                if (_pollManager.AddPoll(poll))  
                    ViewBag.Message = "Poll added successfully!";  
            }  
            return View(poll);  
        }  
    }  
}  

کلاس بالا از تزریق سازنده (constructor injection) برای دسترسی به متدهای تعریف شده در کلاس PollManager استفاده می کند.

متدهای Index() و AddPoll() به سادگی فقط Viewهای مربوطه خود را بازمی گردانند و نه چیز دیگری.

متد سربارگذاری شده (overload)، AddPoll() با صفت [HttpPost] طراحی شده است که مشخص می کند این متد فقط می تواند برای درخواست های POST فراخوانی شود.

این متد همان جایی است که ما درواقع اضافه کردن داده های جدید به دیتابیس را درصورتی که حالت مدل در پست ها معتبر باشد، مدیریت می کنیم.

اضافه کردن یک View

ما لازم داریم که برای پیروی از قرارداد MVC یک فولدر “Views” ایجاد کنیم. در فولدر Views فولدر دیگری با نام “Home” اضافه می کنیم. روی فولدر Home راست کلیک کرده و سپس صفحه MVC View جدید زیر را اضافه کنیم:

  • AddPoll.cshtml
  • Index.cshtml

اضافه کردن یک View
AddPoll View جایی است که ما نظر های جدید را به دیتابیس اضافه می کنیم. Index View جایی است که ما نظر ها را نمایش می دهیم. ساختار Solution ما در حال حاضر باید به این شکل باشد:

نظرسنجی آنلاین

در این مرحله از کار اول روی AddPoll تمرکز خواهیم کرد. حالا فایل AddPoll.cshtml را با کد زیر به روزرسانی می کنیم:

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers  
@model ASPNETCoreSignalRDemo.Models.ViewModels.AddPollViewModel  
  
<h2>Add a New Poll</h2>  
  
<form asp-controller="Home" asp-action="AddPoll" method="post" role="form">  
    <div>  
        @{   
            if (ViewBag.Message != null) { @ViewBag.Message; }  
        }  
        <div asp-validation-summary="All"></div>  
        <div>  
            <label asp-for="Question"></label>  
            <div>  
                <input asp-for="Question"/>  
            </div>  
        </div>  
        <div>  
            <label asp-for="Answer"></label>  
            <div>  
                <textarea asp-for="Answer"></textarea>  
            </div>  
        </div>  
        <div>  
            <div>  
                <input type="submit" value="Add"/>  
            </div>  
        </div>  
    </div>  
</form>  

کد بالا از Tag Helper برای ایجاد و راه اندازی المنت های HTML در View استفاده می کند. Tag Helper ویژگی جدیدی در ASP.NET Core MVC (a.k.a MVC 6) است که می توانیم به عنوان جایگزینی برای MVC HTML Helpers قبلی استفاده نماییم.

فعال سازی MVC و Developer Diagnostics

اشکال زدایی در هر شکلی از برنامه نویسی الزامی است بنابراین ما باید تشخیص خطا در اپلیکیشن ASP.NET Core خود را برای حل مشکلاتی که ممکن است در آینده در حین توسعه با آن مواجه شویم، فعال کنیم.

برای این کار، dependency زیر را به فایل project.json اضافه می کنیم:

“Microsoft.AspNetCore.Diagnostics”: “1.0.0”

خط بالا میان افزار ASP.NET Core برای کنترل استثنائات، صفحات نمایش استثنائات و اطلاعت تشخیص خطا را اضافه می نماید.

برای کسانی که نمی دانند، Web API و MVC در ASP.NET Core ادغام شده اند.

بنابراین به لحاظ فنی، MVC در حال حاضر ادغام شده است چرا که ما یک پروژه ASP.NET Core Web API ایجاد کرده ایم. اما فقط به منظور کامل شدن این آموزش نظرسنجی آنلاین، می خواهیم نشان دهیم که چگونه پیکربندی می شود. حالا Startup.cs را باز کرده و متد Configure() را به صورت زیر تغییر می دهیم،

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)  
        {  
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));  
            loggerFactory.AddDebug();  
  
            if (env.IsDevelopment())  
            {  
                app.UseDeveloperExceptionPage();  
            }  
  
            app.UseMvc(routes =>  
            {  
                routes.MapRoute(  
                    name: "default",  
                    template: "{controller=Home}/{action=Index}/{id?}");  
            });  
}  

دو خط اول logging.ASP.NET Core را که پشتیبانی آن برای گزارش گیری تعبیه شده را فعال می کند، و به ما این امکان را می دهد که از فریمورک گزارش گیری که ترجیح می دهیم به خوبی استفاده کنیم.

App.UseDeveloperExceptionPage() ما را قادر می سازد که جزئیات استثناها را زمانی که اپلیکیشن ما خطایی صادر می کند، در صفحه ببینیم. این متد در اسمبلی Microsoft.AspNet.Diagnostic در دسترس است. خط آخر MVC را با مسیر پیش فرض از پیش تعریف شده فعال میکند. در این مورد /Home/Index صفحه پیش فرض ما خواهد بود.

مسیریابی اپلیکیشن

حالا اپلیکیشن نظرسنجی آنلاین را اجرا می کنیم که فقط تست کنیم آیا اپلیکیشن ما با دسترسی به http://localhost:5000/home/addpoll کار می کند.

ورودی ها را خالی می گذاریم و دکمه اضافه کردن نظر را امتحان می کنیم. با این کار باید پیغام خطای اعتبارسنجی شبیه به شکل زیر نمایش داده شود.

نظرسنجی آنلاین

ادغام ASP.NET SignalR 2

برای این آموزش نظرسنجی آنلاین به خصوص ما از SignalR برای نمایش اتوماتیک نظرجدید ثبت شده در صفحه استفاده می کنیم.

در نظر داشته باشید قالب های پیش فرض برای اپلیکیشن ASP.NET Core 1.0 RTM فقط “netcoreapp1.0” را هدف قرار می دهند.

متاسفانه، ASP.NET SignalR هنوز در .NET Core 1.0 (RTM) پشتیبانی نمی شود بنابراین ما باید به فریمورک .NET 4.6.1 مهاجرت نماییم تا قادر به استفاده از ویژگی های ASP.NET SignalR باشیم.

نکته: ما در آموزش نظرسنجی آنلاین با هدف قرار دادن فریمورک net461، قابلیت پشتیبانی از تمامی پلت فرم ها را در اپلیکیشن خود از دست می دهیم.

به هرحال وقتی که SignalR 3 پشتیبانی می شود، مطمئن هستیم که برای ادغام آن فقط به چند ترفند نیاز است بنابراین اپلیکیشن نظرسنجی آنلاین ما می تواند با هدف قرار دادن فریمورک netcore1.0 روی چندین پلت فرم اجرا شود.

خب اجازه دهید که ادامه دهیم و ببینیم که چگونه می توانیم از قدرت SignalR در اپلیکیشن ASP.NET Core خود استفاده کنیم.

اگر بخواهیم چندین فریمورک را هدف قرار دهیم پس می توانیم ابتدا با اضافه کردن .NET framework کامل به لیست project.json (به عنوان مثال “net461” برای .NET Framework 4.6.1) در زیرشاخه “frameworks” این کار را انجام دهیم.

در نظر داشته باشید وابستگی “Microsoft.NETCore.App” از بخش “dependencies” سراسری را به یک بخش “dependencies” جدید زیر شاخه “netcoreapp1.0” در قسمت “frameworks” جابجا می کنیم، سپس می توانیم وابستگی را به ASP.NEET SignalR در آموزش نظرسنجی آنلاین زیر را به “net461” اضافه کنیم.

به این ترتیب بخش “frameworks” مربوط به فایل project.json به شکل زیر می شود:

"frameworks": {  
    "netcoreapp1.0": {  
      "imports": [  
        "dotnet5.6",  
        "dnxcore50",  
        "portable-net45+win8"  
      ],  
      "dependencies": {  
        "Microsoft.NETCore.App": {  
          "version": "1.0.0",  
          "type": "platform"  
        }  
      }  
    },  
    "net461": {  
      "dependencies": {  
        "Microsoft.AspNet.SignalR": "2.2.0"  
      }  
    }  
  },  

برای کاهش پیچیدگی و ساده سازی آموزش، تصمیم گرفتیم فقط فریمورک “net461” را هدف قرار دهیم. بنابراین وابستگی “netcoreapp1.0” را در این لحظه حذف کرده ایم و وابستگی های زیر را اضافه کردیم:

  •  “۱.۰.۰”: “Microsoft.AspNetCore.StaticFiles”
  • “۲.۲.۰”: “Microsoft.AspNet.SignalR”
  •  “۱.۲.۲”: “Microsoft.AspNet.SignalR.Owin”
  •  “۱.۰.۰”: “Microsoft.AspNet.Owin “

ادغام Microsoft.AspNetCore.StaticFiles اپلیکیشن ما را قادر به استفاده از جاوا اسکریپت، CSS و فایل های تصویری به صورت مستقیم در کلاینت ها می کند.

همچنین ما باید این ویژگی را فعال کنیم زیرا قصد داریم فایل SignalR JavaScript را در wwwroot اضافه کنیم.

Microsoft.AspNet.SignalR مسئول pull کردن در کامپوننت های سرور است و کلاینت جاوااسکریپت موردنیاز برای استفاده از SignalR در اپلیکیشن ماست.

Microsoft.AspNet.SignalR.Owin شامل کامپوننت های OWIN برای ASP.NET SignalR می باشد.

Microsoft.AspNetCore.Owin کامپوننتی برای میان افزار OWIN در اپلیکیشن ASP.NET Core است و برای اجرای میان افزار ASP.NET Core در یک اپلیکیشن OWIN می باشد.

حالا فایل project.json ما به صورت زیر درمی آید:

{  
  "dependencies": {  
    "Microsoft.AspNetCore.Mvc": "1.0.0",  
    "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",  
    "Microsoft.AspNetCore.Server.Kestrel": "1.0.0",  
    "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",  
    "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0",  
    "Microsoft.Extensions.Configuration.Json": "1.0.0",  
    "Microsoft.Extensions.Logging": "1.0.0",  
    "Microsoft.Extensions.Logging.Console": "1.0.0",  
    "Microsoft.Extensions.Logging.Debug": "1.0.0",  
    "Microsoft.EntityFrameworkCore.SqlServer": "1.0.0",  
    "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final",  
    "Microsoft.EntityFrameworkCore.SqlServer.Design": "1.0.0",  
    "Microsoft.AspNetCore.Diagnostics": "1.0.0",  
    "Microsoft.AspNetCore.StaticFiles": "1.0.0",  
    "Microsoft.AspNet.SignalR": "2.2.0",  
    "Microsoft.AspNet.SignalR.Owin": "1.2.2",  
    "Microsoft.AspNetCore.Owin": "1.0.0"  
  },  
  
  "tools": {  
    "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final",  
    "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final"  
  },  
  
  "frameworks": {  
    "net461": {}  
  },  
  
  "buildOptions": {  
    "emitEntryPoint": true,  
    "preserveCompilationContext": true  
  },  
  
  "runtimeOptions": {  
    "gcServer": true  
  },  
  
  "publishOptions": {  
    "include": [  
      "wwwroot",  
      "Views",  
      "appsettings.json",  
      "web.config"  
    ]  
  },  
  
  "scripts": {  
    "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]  
  }  
}  

توجه داشته باشید که اگر بخواهید می توانید SignalR و سایر پکیج ها را از طریق NPM نصب نمایید. تصویر زیر را مشاهده نمایید:

نظرسنجی آنلاین

تا زمان نوشتن این آموزش، آخرین نسخه از ASP.NET SignalR نسخه ۲.۲ است. زمانی که رفرنس های موردنیاز نصب شد، باید بتوانیم آن ها را به صورت زیر اضافه شده به پروژه ببینیم:

نظرسنجی آنلاین

ادغام پکیج های سمت کلاینت – jQuery و SignalR Scripts

به منظور استفاده از ویژگی های سمت کلاینت SignalR ما باید در View خود به وابستگی های زیر ارجاع دهیم:

  •  jQuery
  • jQuery.signalR
  • /signalr/hub

در این آموزش نظرسنجی آنلاین ، قصد داریم از jQuery CDN برای ارجاع دادن به کتابخانه jQuery استفاه نماییم. به خاطر داشته باشید که می توانید برای مدیریت منابع سمت کلاینت مانند jQuery در پروژه خود از مرورگر استفاده نمایید.

حالا قسمت ترفندی این آموزش اضافه کردن فایل SignalR 2 Core JavaScript به پروژه است. اسکریپت های کلاینت SignalR Core مربوطه در کامپوننت های Microsoft.AspNet.SignalR.JS اضافه می شوند.

این کامپوننت به طور اتوماتیک به عنوان وابستگی کامپوننت Microsoft.AspNet.SignalR اضافه می شود. حالا از طریق مکان فیزیکی زیر در ماشین خود، آن را مرور می کنیم:

C:\Users\<UserName>\.nuget\packages\Microsoft.AspNet.SignalR.JS\2.2.0\content

سپس فولدر Scripts را کپی کرده و در فولدر wwwroot در پروژه خود قرار می دهیم. در این مثال در فولدر “ASPNTCoreSignalRDemo/wwwroot” قرار می دهیم. حالا در پروژه باید چنین ساختاری داشته باشیم:

نظرسنجی آنلاین

رفرنس به پروکسی تولید شده SignalR به طور داینامیک کد جاوا اسکریپت را تولید می کند، اما نه به یک فایل فیزیکی.

SignalR کد جاوا اسکریپت را در زمان اجرا ایجاد می کند و در پاسخ به آدرس “/signalr/hubs” به کلاینت می دهد.

ایجاد یک میان افزار برای نگاشت SignalR

ما باید یک میان افزار برای SignalR ایجاد کنیم بنابراین آن را برای استفاده آن توسط ایجاد یک متد بسطی IApplicationBuilder پیکربندی می کنیم.

حالا یک کلاس جدید در فولدر ریشه اپلیکیشن ایجاد می کنیم و نام آن را “AppBuilderExtensions” می گذاریم. کد آن به شکل زیر است:

using Owin;   
using System;   
using System.Collections.Generic;   
using System.Threading.Tasks;   
using Microsoft.AspNetCore.Builder;   
  
namespace ASPNETCoreSignalRDemo  
{  
    using Microsoft.Owin.Builder;  
    using AppFunc = Func<IDictionary<string, object>, Task>;  
  
    public static class AppBuilderExtensions   
    {   
        public static IApplicationBuilder UseAppBuilder(this IApplicationBuilder app, Action<IAppBuilder> configure)   
        {   
            app.UseOwin(addToPipeline =>   
            {   
                addToPipeline(next =>   
                {   
                    var appBuilder = new AppBuilder();   
                    appBuilder.Properties["builder.DefaultApp"] = next;   
   
                    configure(appBuilder);   
   
                    return appBuilder.Build<AppFunc>();   
                });   
            });   
   
            return app;   
        }   
   
        public static void UseSignalR2(this IApplicationBuilder app)   
        {   
            app.UseAppBuilder(appBuilder => appBuilder.MapSignalR());   
        }   
    }  
}  

متد بسطی UseAppBuilder با استفاده از متد بسطی UseOwin() یک میان افزار جدید به ASP.NET می افزاید. و با فراخوانی متد UseAppBuilder() در متد بسطی UseSignalR2() میان افزار MapSignalR() را اضافه می کند.

اضافه کردن SignalR به روند توسعه

حالا فایل Startup.cs را باز کرده و متد Configure را به شکل زیر تغییر می دهیم:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)  
        {  
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));  
            loggerFactory.AddDebug();  
  
            if (env.IsDevelopment())  
            {  
                app.UseDeveloperExceptionPage();  
            }  
  
            app.UseStaticFiles();  
            app.UseMvc(routes =>  
            {  
                routes.MapRoute(  
                    name: "default",  
                    template: "{controller=Home}/{action=Index}/{id?}");  
            });  
             
            app.UseSignalR2();  
        }  

فراخوانی متد app.UseSignalR2() میان افزار SignalR را به روند توسعه اپلیکیشن اضافه می کند.

ساخت یک Hub

فولدر جدیدی با نام “Hubs” در ریشه اپلیکیشن ایجاد کرده و سپس یک کلاس جدید اضافه می کنیم، و نام آن را “PollHub” می گذاریم. ساختار پروژه به شکل زیر در می آید:

نظرسنجی آنلاین

حالا کد زیر را به کلاس “PollHub” اضافه می کنیم:

using Microsoft.AspNet.SignalR;  
  
namespace ASPNETCoreSignalRDemo.Hubs  
{  
    public class PollHub: Hub  
    {  
        public static void FetchPoll()  
        {  
            IHubContext context = GlobalHost.ConnectionManager.GetHubContext<PollHub>();  
            context.Clients.All.displayPoll();  
        }  
    }  
}  

اگر بخواهیم یک مرور کوتاه روی Hub داشته باشیم، Hub قطعه مرکزی SignalR است. مانند Controller در ASP.NET MVC، یک Hub وظیفه دریافت ورودی ها و تولید خروجی برای کلاینت را به عهده دارد. متدهای درون Hub می توانند از سرور یا کلاینت فراخوانی شوند.

فراخوانی یک متد Hub

در این آموزش می خواهیم ببینیم که چگونه یک متد از Hub را در controller action فراخوانی نماییم. همچنین می توانیم از این تکنیک استفاده کنیم اگر به عنوان مثال، شما یک اپلیکیشن موبایل داشته باشید که داده ها را با استفاده از فراخوانی های Web API همگام سازی می کند و نیاز به نمایش بلادرنگ نتایج در وب سایت خود داشته باشید.

حالا فایل HomeController را باز کرده و متد AddPoll() را به شکل زیر تغییر می دهیم:

[HttpPost]  
       [ValidateAntiForgeryToken]  
       public IActionResult AddPoll(AddPollViewModel poll)  
       {  
           if (ModelState.IsValid) {  
               if (_pollManager.AddPoll(poll))  
               {  
                   ViewBag.Message = "Poll added successfully!";  
                   ASPNETCoreSignalRDemo.Hubs.PollHub.FetchPoll();  
               }        
           }  
           return View(poll);  
       }  

فراخوانی متد FetchPoll() از Hub، displayPoll() را فراخوانی خواهد کرد، و تمامی کلاینت های متصل به روزرسانی ها را دریافت خواهند کرد.

اگر در این مورد از AJAX استفاده می نمایید و می خواهید متد FetchPoll() را در جاوا اسکریپت خود اجرا نمایید، می توانید آن را به شکل زیر فراخوانی کنید:


var poll = $.connection.pollHub;  
poll.server.fetchPoll();  

ایجاد Web API

فولدر جدیدی با نام “API” ایجاد کرده و یک کلاس Web API Controller با نام “PollController” به آن اضافه می کنیم. ساختار پروژه به شکل زیر خواهد بود:

نظرسنجی آنلاین

 

کدهای داخل کلاس PollController را به شکل زیر تغییر می دهیم:

using System.Collections.Generic;  
using System.Linq;  
using Microsoft.AspNetCore.Mvc;  
using ASPNETCoreSignalRDemo.Models.ViewModels;  
using ASPNETCoreSignalRDemo.Models;  
  
namespace ASPNETCoreSignalRDemo.API  
{  
    [Route("api/[controller]")]  
    public class PollController : Controller  
    {  
        private readonly IPollManager _pollManager;  
  
        public PollController(IPollManager pollManager)  
        {  
            _pollManager = pollManager;  
        }  
  
        [HttpGet]  
        public IEnumerable<PollDetailsViewModel> Get()  
        {  
           var res =  _pollManager.GetActivePoll();  
           return res.ToList();  
        }  
      
    }  
}  

کلاس بالا از صفت Routing استفاده می کند تا مشخص کند که این کلاس یک API با طراحی این صفت است:

[Route(“api/[controller]”)]

درست مثل HomeController ما، این نیز از تزریق سازنده برای مقداردهی اولیه PollManager استفاده می کند. متد Get() به سادگی نتیجه داده های رای را از دیتابیس برمی گرداند.

نمایش نظرسنجی آنلاین

Index.cshtml را باز کرده و کد آن را به شکل زیر تغییر می دهیم:

<script src="https://code.jquery.com/jquery-2.2.4.min.js" integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44=" crossorigin="anonymous"></script>  
<script src="../Scripts/jquery.signalR-2.2.0.js"></script>  
<script src="../signalr/hubs"></script>  
  
<script>  
    $(function () {  
        var poll = $.connection.pollHub;  
  
        poll.client.displayPoll = function () {  
            LoadActivePoll();  
        };  
  
        $.connection.hub.start();  
        LoadActivePoll();  
    });  
  
    function LoadActivePoll() {  
        var $div = $("#divQuestion");  
        var $tbl = $("#tblPoll");  
        $.ajax({  
            url: '../api/poll',  
            type: 'GET',  
            datatype: 'json',  
            success: function (data) {  
                if (data.length > 0) {  
                    $div.html('<h3>' + data[0].question + '</h3>');  
                    $tbl.empty();  
                    var rows = [];  
                    var poll = data[0].pollOption;  
                    for (var i = 0; i < poll.length; i++) {  
                        rows.push('<tbody><tr><td>' + poll[i].answers + '</td><td><input name="poll" type="radio"/></td></tr></tbody>');  
                    }  
                    $tbl.append(rows.join(''));  
                }  
            }  
        });  
    }  
</script>  
  
<h2>ASP.NET Core Online Poll System with SignalR 2</h2>  
<div id="divQuestion"></div>  
<table id="tblPoll"></table>  

به ترتیب اضافه کردن رفرنس های اسکریپت ها دقت داشته باشید. jQuery باید اول از همه اضافه شود، سپس SignalR Core JavaScript و درنهایت SignalR Hubs script اضافه می شود.

تابع LoadActivePoll() از jQuery AJAX برای فراخوانی یک Web API از طریق درخواست AJAX GET استفاده می کند. اگر هر داده ای پاسخی به این درخواست وجود داشته باشد، این تابع با زدن حلقه تکرار روی سطرها یک HTML تولید می کند.

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

خلاصه

در این مقاله آموزشی نظرسنجی آنلاین ایجاد یک core foundation اپلیکیشن را با شروع از ساخت یک دیتابیس جدید، ساخت یک پروژه ASP.NET Core و تنظیمات Data Access با استفاده از EF Core به اتمام رساندیم.

همچنین یاد گرفتیم که چگونه با استفاده از ASP.NET SignalR 2 یک صفحه ساده برای ساخت یک نظرسنجی آنلاین و ثبت یک رای جدید و صفحه ای برای نمایش رای ثبت شده به صورت بلادرنگ بسازیم.

جهت دانلود سورس کد نظرسنجی آنلاین میتوانید به لینک مراجعه کنید.همچنین جهت دانلود سورس .NET Core میتوانید به لینک مراجعه کنید.

زهره سلطانیان

نوشته‌های مرتبط

دیدگاه‌ها

*
*

این سایت از اکیسمت برای کاهش هرزنامه استفاده می کند. بیاموزید که چگونه اطلاعات دیدگاه های شما پردازش می‌شوند.