سیستم امتیازدهی در ASP.Net ابزاری است که به کاربران این امکان را می دهد که اعلام کنند یک سرویس یا محصول، خوب، بد یا خیلی بد می باشد. همچنین به صاحبان مشاغل کمک می کند تا سرویس و محصولات خود را بر مبنای این امتیازدهی آنالیز کرده و محصولات بهتری ارائه دهند. در این مقاله به شما نشان خواهیم داد که چگونه یک سیستم امتیازدهی ۵ ستاره ساده با استفاده از jQuery Ajax و Web API در کنترل GridView اضافه کنیم.
مثال بالا لیستی از کتاب ها را در کنترل GridView با امکان امتیازدهی نمایش می دهد. گزینه امتیازدهی در هر سطر grid نشان داده خواهد شد. ستاره ها به صورت image هستند. در اینجا Web API نقش مهمی در ذخیره امتیاز کاربران (از ۱ تا ۵) دارد و دو مقدار امتیاز کل و امتیاز میانگین را برمی گرداند، در یک جدول SQL Server ذخیره می کند. واضح است که اگر از Web API به عنوان یک وب سرویس استفاده کنیم سپس بهترین راه برای ارتباط با سرویس، استفاده از jQuery Ajax است.
جدول های SQL Server
ابتدا دو جدول در دیتابیس SQL Server خود ایجاد می کنیم. جدول اول لیست کتاب هایی خواهد بود که در Grid نمایش می دهیم. جدول دیگر امتیاز هر یک از کتاب ها را بر اساس id آن ها ذخیره خواهد کرد.
CREATE TABLE [dbo].[Books]( [BookID] [int] IDENTITY(1,1) NOT NULL, [BookName] [varchar](50) NULL, [Category] [varchar](50) NULL, [Price] [numeric](18, 2) NULL, [Price_Range] [varchar](20) NULL, PRIMARY KEY CLUSTERED ( [BookID] ASC ) ) ON [PRIMARY] GO -- ADD FEW ROWS TO THE TABLE. -- SQL SERVER 2008 AND ABOVE. INSERT INTO dbo.Books (BookName, Category, Price, Price_Range) VALUES ('Computer Architecture', 'Computers', 125.6, '100-150'), ('Advanced Composite Materials', 'Science', 172.56, '150-200'), ('Asp.Net 4 Blue Book', 'Programming', 56.00, '50-100'), ('Strategies Unplugged', 'Science', 99.99, '50-100'), ('Teaching Science', 'Science', 164.10, '150-200'), ('Challenging Times', 'Business', 150.70, '150-200'), ('Circuit Bending', 'Science', 112.00, '100-150'), ('Popular Science', 'Science', 210.40, '200-250'), ('ADOBE Premiere', 'Computers', 62.20, '50-100') -- SQL SERVER 2005 AND BEFORE. INSERT INTO dbo.Books (BookName, Category, Price, Price_Range) SELECT 'Computer Architecture', 'Computers', 125.6, '100-150' INSERT INTO dbo.Books (BookName, Category, Price, Price_Range) SELECT 'Advanced Composite Materials', 'Science', 172.56, '150-200' INSERT INTO dbo.Books (BookName, Category, Price, Price_Range) SELECT 'Asp.Net 4 Blue Book', 'Programming', 56.00, '50-100' INSERT INTO dbo.Books (BookName, Category, Price, Price_Range) SELECT 'Strategies Unplugged', 'Science', 99.99, '50-100' INSERT INTO dbo.Books (BookName, Category, Price, Price_Range) SELECT 'Teaching Science', 'Science', 164.10, '150-200' INSERT INTO dbo.Books (BookName, Category, Price, Price_Range) SELECT 'Challenging Times', 'Business', 150.70, '150-200' INSERT INTO dbo.Books (BookName, Category, Price, Price_Range) SELECT 'Circuit Bending', 'Science', 112.00, '100-150' INSERT INTO dbo.Books (BookName, Category, Price, Price_Range) SELECT 'Popular Science', 'Science', 210.40, '200-250' INSERT INTO dbo.Books (BookName, Category, Price, Price_Range) SELECT 'ADOBE Premiere', 'Computers', 62.20, '50-100'
حالا جدول دوم با نام dbo.Books_Rating را ایجاد می کنیم.
CREATE TABLE dbo.Books_Rating( RateID INT IDENTITY(1,1) NOT NULL, BookID INT NOT NULL, Rating INT NOT NULL )
CSS و Markup
مایکروسافت ابزارهای مفید متعددی برای ما فراهم کرده است که یکی از آن ها GridView است. این ابزار بسیار انعطاف پذیر می باشد، و به راحتی می توانیم یک جدول دیتابیس را به GridView متصل (Bind) کنیم. در این جا برای پر کردن داده در GridView در زمان بارگزاری اولیه صفحه و رفتن به صفحه GridView Pages از کنترل SqlDataSource استفاده کردیم.
اتصال داده ها به GridView با استفاده از SqlDataSource
<!DOCTYPE html> <html> <head> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script> <style> .container { font:13px Verdana; width:600px; } .grid { width:100%; font:inherit; background-color:#FFF; border:solid 1px #525252; } .grid td { font:inherit; padding:2px; border:solid 1px #C1C1C1; color:#333; text-align:center; text-transform:capitalize; } .grid th { padding:3px; color:#FFF; background:#424242; border-left:solid 1px #525252; font:inherit; text-align:center; text-transform:uppercase; } .rating { background:#FFF; border:none; display:block; } .rating img { display:inline-block; width:18px; height:17px; border:0; cursor:pointer; } /*SHOW FILLED STAR IMAGE WHEN MOUSE MOVES OVER THE IMAGES*/ .rating img:hover { background:#FFF url(star-fill.png); } </style> </head> <body> <form runat="server"> <div> <div class="container"> <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" CssClass="grid" AllowPaging="true" PageSize="5" DataSourceID="SqlDataSource1" DataKeyNames="BookID"> <Columns> <asp:BoundField DataField="BookID" HeaderText="Book ID" SortExpression="BookID" InsertVisible="False" ReadOnly="True" /> <asp:BoundField DataField="BookName" HeaderText="Book Name" SortExpression="BookName" /> <asp:BoundField DataField="Category" HeaderText="Category" SortExpression="Category" /> <asp:TemplateField HeaderText="Click to Rate"> <ItemTemplate> <div style="display:inline-table;width:auto;" id='<%#Eval("BookID") %>'> <%--THE RATING STARS--%> <div class="rating"> <img src="" alt="1" /> <img src="" alt="2" /> <img src="" alt="3" /> <img src="" alt="4" /> <img src="" alt="5" /> </div> <%-- SHOW AVERAGE RATE --%> <div style="text-align:center;margin:5px 0 0 0;"> Avg. Rating: <span id="avgRate"><%#Eval("AverageRate")%></span> </div> <%-- SHOW TOTAL RATINGS --%> <div style="text-align:center;margin:0 0 10px 0;"> Based on <span id="totRatings" style="font-weight:bold;"><%#Eval("TotalRatings")%></span> Ratings </div> </div> </ItemTemplate> </asp:TemplateField> </Columns> </asp:GridView> <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:DNAConnectionString %>" <%--THE SQL QUERY THAT WILL FETCH TOTAL AND AVERAGE RATINGS.--%> SelectCommand="SELECT B.BookID, B.BookName, B.Category, COUNT(BR.Rating) TotalRatings, ISNULL(CAST(CAST(SUM(BR.Rating) AS NUMERIC(5,2)) / COUNT(BR.Rating) AS NUMERIC(3,1)), 0) AverageRate FROM Books B LEFT OUTER JOIN Books_Rating BR ON B.BookID = BR.BookID GROUP BY B.BookID, B.BookName, B.Category"> </asp:SqlDataSource> </div> </div> </form> </body>
Property مربوط به کنترل SqlDataSource با نام SelectCommand یک کوئری SQL دارد که اطلاعات کتاب ها را به همراه امتیاز میانگین و امتیاز کل برمی گرداند.
داخل تگ <Columns> مربوط به GridView یک تگ <asp:TemplateField> با عنوان “Click to Rate” اضافه می کنیم. این تگ به ما امکان تعریف فیلدهای دلخواه در کنار فیلدهای پیش فرض را می دهد.
داخل تگ <ItemTemplate> چند Div برای اضافه کردن عکس ۵ ستاره در هر سطر و نمایش امتیاز کل و امتیاز میانگین داریم.
Web API (MVC)
در اینجا فرض بر این است که شما دانش مختصری درباره ایجاد Web API در ASP.Net دارید.
کلاس Model به نام “Books.cs” در C#
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace BooksApp.Models { public class Books { private int m_TotalRatings; public int TotalRatings { get { return m_TotalRatings; } set { m_TotalRatings = value; } } private double m_AverateRatings; public double AvgRatings { get { return m_AverateRatings; } set { m_AverateRatings = value; } } } }
کلاس Model به نام “Books.cs” درVB.Net
Imports System.Web Namespace BooksApp.Models Public Class Books Public Property TotalRatings() As Integer Get Return m_TotalRatings End Get Set(value As Integer) m_TotalRatings = value End Set End Property Private m_TotalRatings As Integer Public Property AvgRatings() As Double Get Return m_AverateRatings End Get Set(value As Double) m_AverateRatings = value End Set End Property Private m_AverateRatings As Double End Class End Namespace
Controller با نام “BooksController.cs” در C#
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Web.Http; using BooksApp.Models; using System.Data.SqlClient; namespace BooksApp.Controllers { public class BooksController : ApiController { List<Books> BooksRatings = new List<Books>(); string sConnString = "Data Source=pc;Persist Security Info=False;" + "Initial Catalog=DNA;User Id=sa;Password=;Connect Timeout=30;"; public IEnumerable<Books> Get(int iBookID, int iUserRating) { if (SaveRatings(iBookID, iUserRating)) { getTotalRatings(iBookID); } return BooksRatings; } // SAVE RATINGS IN THE TABLE. private bool SaveRatings(int iBookID, int iUR) { bool functionReturnValue = false; functionReturnValue = false; SqlConnection myConn = new SqlConnection(sConnString); myConn.Open(); SqlCommand objComm = new SqlCommand("INSERT INTO dbo.Books_Rating (BookID, Rating) " + "VALUES (" + iBookID + ", " + iUR + ")", myConn); dynamic i = objComm.ExecuteNonQuery(); myConn.Close(); if (i >= 1) { return true; } return functionReturnValue; } // RETURN AVERAGE AND TOTAL RATINGS. public void getTotalRatings(int iBookID) { string sQuery = "SELECT COUNT(BR.Rating) TotalRatings, " + "ISNULL(CAST(CAST(SUM(BR.Rating) AS NUMERIC(5,2)) / COUNT(BR.Rating) AS NUMERIC(3,1)), 0) AverageRate " + "FROM dbo.Books_Rating BR " + "WHERE BR.BookID = " + iBookID; SqlConnection myConn = new SqlConnection(sConnString); SqlCommand objComm = new SqlCommand(sQuery, myConn); myConn.Open(); SqlDataReader reader = objComm.ExecuteReader(); if (reader.Read()) { BooksRatings.Add(new Books { TotalRatings = Convert.ToInt32(reader["TotalRatings"]), AvgRatings = Convert.ToDouble(reader["AverageRate"]) }); } myConn.Close(); } } }
Controller با نام “BooksController.cs” درVB.Net
Option Explicit On Imports System.Web.Http Imports BooksApp.BooksApp.Models Imports System.Data.SqlClient Namespace BooksApp Public Class BooksController Inherits ApiController Dim BooksRatings As New List(Of Books)() Dim sConnString As String = "Data Source=pc;Persist Security Info=False;" & _ "Initial Catalog=DNA;User Id=sa;Password=;Connect Timeout=30;" Public Function [Get](ByVal iBookID As Integer, ByVal iUserRating As Integer) As IEnumerable(Of Books) If SaveRatings(iBookID, iUserRating) Then getTotalRatings(iBookID) End If Return BooksRatings End Function ' SAVE RATINGS IN THE TABLE. Private Function SaveRatings(ByVal iBookID As Integer, ByVal iUR As Integer) As Boolean SaveRatings = False Dim myConn As New SqlConnection(sConnString) myConn.Open() Dim objComm As New SqlCommand("INSERT INTO dbo.Books_Rating (BookID, Rating) " & _ "VALUES (" & iBookID & ", " & iUR & ")", myConn) Dim i = objComm.ExecuteNonQuery() myConn.Close() If i >= 1 Then Return True End If End Function ' RETURN AVERAGE AND TOTAL RATINGS. Public Sub getTotalRatings(ByVal iBookID As Integer) Dim sQuery As String = "SELECT COUNT(BR.Rating) TotalRatings, " & _ "ISNULL(CAST(CAST(SUM(BR.Rating) AS NUMERIC(5,2)) / COUNT(BR.Rating) AS NUMERIC(3,1)), 0) AverageRate " & _ "FROM dbo.Books_Rating BR " & _ "WHERE BR.BookID = " & iBookID Dim myConn As New SqlConnection(sConnString) Dim objComm As New SqlCommand(sQuery, myConn) myConn.Open() Dim reader As SqlDataReader = objComm.ExecuteReader() If reader.Read() Then BooksRatings.Add(New Books() With { _ .TotalRatings = CInt(reader("TotalRatings")), _ .AvgRatings = reader("AverageRate") _ }) End If myConn.Close() End Sub End Class End Namespace
فایل WebApiConfig
ما باید جدول routing ای را که در فایل WebApiConfig داریم، به صورتی تغییر دهیم که چندین پارامتر (bookid و rating) را به Controller ارسال کند.
کد C#:
namespace BooksApp { public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{iBookID}/{iUserRating}", defaults: new { iBookID = RouteParameter.Optional, iUserRating = RouteParameter.Optional } ); } } }
کد VB.Net:
Public Class WebApiConfig Public Shared Sub Register(ByVal config As HttpConfiguration) config.Routes.MapHttpRoute( _ name:="DefaultApi", _ routeTemplate:="api/{controller}/{iBookID}/{iUserRating}", _ defaults:=New With {.iBookID = RouteParameter.Optional, .iUserRating = RouteParameter.Optional} _ ) End Sub End Class
در نهایت، اسکریپت جی کوئری با Ajax که متدهای وب سرویس را برای به روزرسانی امتیازدهی جدید فراخوانی می کند و همچنین امتاز کل و امتیاز میانگین را بازیابی می کند.
<script> $(document).ready(function () { $('img').attr('src', 'star-empty.png'); // CLEAR ALL THE STARS. // SHOW STARS ACCORDING TO AVERAGE RATE OF EACH BOOK. $('#GridView1 tr').each(function (index, value) { var avg = $(this).find('#avgRate').text(); $(this).find('.rating > img').each(function () { if ($(this).attr('alt') <= avg) { $(this).attr('src', 'star-fill.png'); } }); }); // SAVE USER SELECTED RATE IN DB. // GET TOTAL AND AVERAGE RATINGS FROM DB AND UPDATE THE ROW. $('img').click(function () { var userRating = $(this).attr('alt'); var bookID = $(this).parent().parent().attr('id'); $.ajax({ type: "GET", url: 'http://localhost:38331/api/books/', data: { iBookID: bookID, iUserRating: userRating }, success: function (data) { $.map(data, function () { // REFRESH AVERAGE AND TOTAL RATINGS FOR THE ROW. $('#' + bookID + ' #avgRate').text(data[0].AvgRatings); $('#' + bookID + ' #totRatings').text(data[0].TotalRatings); // UPDATE STARS RATING. $('#' + bookID).find('.rating > img').each(function () { if ($(this).attr('alt') <= data[0].AvgRatings) { $(this).attr('src', 'star-fill.png'); } else $(this).attr('src', 'star-empty.png'); }); }); }, error: function (XMLHttpRequest, textStatus, errorThrown) { alert(textStatus); } }); }); }); </script>
هیچ دیدگاهی نوشته نشده است.