به نظر شما استفاده از یک TagHelper سفارشی راه درستی هست برای حل این مورد
public class AnchorTagHelper : TagHelper { /// <summary> /// The name of the action method. /// </summary> [HtmlAttributeName ("asp-action")] public string Action { get; set; } /// <summary> /// The name of the controller. /// </summary> [HtmlAttributeName ("asp-controller")] public string Controller { get; set; } /// <summary> /// The name of the area. /// </summary> [HtmlAttributeName ("asp-area")] public string Area { get; set; } [HtmlAttributeName ("asp-route")] public string Route { get; set; } // Can be async Task public override void Process (TagHelperContext context, TagHelperOutput output) { output.TagName = "a"; string result = string.Empty; if (!string.IsNullOrWhiteSpace (Area)) { result += "/" + Area; } if (!string.IsNullOrWhiteSpace (Controller)) { result += "/" + Controller; } if (!string.IsNullOrWhiteSpace (Action)) { result += "/" + Action; } if (!string.IsNullOrWhiteSpace (Route)) { Route = ToFriendlyHref (Route); result += "/" + Route; } output.Attributes.SetAttribute ("href", result.ToLowerInvariant ()); //output.Content.SetContent (currentAttribute.ToString ()); } private string ToFriendlyHref (object value) { string text = value.ToString (); List<char> illegalChars = new List<char> () { ' ', '.', '#', '%', '&', '*', '{', '}', '\\', ':', '<', '>', '?', ';', '@', '=', '+', '$', ',' }; illegalChars.ForEach (c => { text = text.Replace (c.ToString (), "-"); }); return text; } }
نظرات مطالب
رسم نمودار توسط Kendo Chart
با سلام و تشکر
من مشکل مرتب سازی فیلدهای از نوع عددی (int) در Kendo Chart دارم. همانند شکل زیر
کدهای نوشته شده به شکل زیر هستند (Year از جنس عدد هست)
ضمنا ViewModel هم به صورت زیر میباشد
ممنون از راهنمائی تون.
من مشکل مرتب سازی فیلدهای از نوع عددی (int) در Kendo Chart دارم. همانند شکل زیر
کدهای نوشته شده به شکل زیر هستند (Year از جنس عدد هست)
$(document).ready(function () { //چارت 4 $.ajax({ type: 'POST', url: '@Url.Action("TierStatistics4", "Dashboard", new { area = "Tier" })', dataType: 'json', data: { CostCenterId: $("#CostCenterId").val(), QueryIndex: $("#QueryIndex").val() }, success: function (data) { dataSource = new kendo.data.DataSource({ data: data, group: { field: "Series" }, sort: { field: "Year", dir: "desc" } }); $("#chart4").kendoChart({ title: { text: "آمار تعداد/هزینه(ریال) تایر مصرفی شعب به تفکیک مراکز هزینه و ماههای سال", font: "irsans", }, dataSource: dataSource, series: [{ type: "column", field: "Value", categoryField: "Year", name: "#= group.value #", }], categoryAxis: { font: "irsans", labels: { font: "irsans" } }, valueAxis: { labels: { font: "irsans", visible: true, } }, seriesDefaults: { style: "smooth", labels: { position: "Bottom", visible: false, fromat: "{0:n0}", font: "irsans", font: "irsans", format: "{0:n0}", } }, legend: { position: "top", labels: { font: "irsans" } }, tooltip: { visible: true, format: "{0:n0}", template: "#= series.name #: #= value #", font: "irsans", } }) }, error: function (ex) { alert('خطا در بازیابی اطلاعات' + ex); } }); return false; });
public class DashoardViewModel : System.Object { public DashoardThirdViewModel() { } public string Series { get; set; } // ********** public int Year { get; set; } //********** public long Value { get; set; } // ********** }
ممنون از راهنمائی تون.
مطالب دورهها
نگاهی به SignalR Clients
در قسمت قبل موفق به ایجاد اولین Hub خود شدیم. در ادامه، برای تکمیل برنامه نیاز است تا کلاینتی را نیز برای آن تهیه کنیم.
مصرف کنندگان یک Hub میتوانند انواع و اقسام برنامههای کلاینت مانند jQuery Clients و یا حتی یک برنامه کنسول ساده باشند و همچنین Hubهای دیگر نیز قابلیت استفاده از این امکانات Hubهای موجود را دارند. تیم SignalR امکان استفاده از Hubهای آنرا در برنامههای دات نت 4 به بعد، برنامههای WinRT، ویندوز فون 8، سیلورلایت 5، jQuery و همچنین برنامههای CPP نیز مهیا کردهاند. به علاوه گروههای مختلف نیز با توجه به سورس باز بودن این مجموعه، کلاینتهای iOS Native، iOS via Mono و Android via Mono را نیز به این لیست اضافه کردهاند.
بررسی کلاینتهای jQuery
با توجه به پروتکل مبتنی بر JSON سیگنالآر، استفاده از آن در کتابخانههای جاوا اسکریپتی همانند jQuery نیز به سادگی مهیا است. برای نصب آن نیاز است در کنسول پاور شل نوگت، دستور زیر را صادر کنید:
برای نمونه به solution پروژه قبل، یک برنامه وب خالی دیگر را اضافه کرده و سپس دستور فوق را بر روی آن اجرا نمائید. در این حالت فقط باید دقت داشت که فرامین بر روی کدام پروژه اجرا میشوند:
با استفاده از افزونه SignalR jQuery، به دو طریق میتوان به یک Hub اتصال برقرار کرد:
الف) استفاده از فایل proxy تولید شده آن (این فایل، در زمان اجرای برنامه تولید میشود و یا امکان استفاده از آن به کمک ابزارهای کمکی نیز وجود دارد)
نمونهای از آنرا در قسمت قبل ملاحظه کردید؛ همان فایل تولید شده در مسیر /signalr/hubs برنامه. به نوعی به آن Service contract نیز گفته میشود (ارائه متادیتا و قراردادهای کار با یک سرویس Hub). این فایل همانطور که عنوان شد به صورت پویا در زمان اجرای برنامه ایجاد میشود.
امکان تولید آن توسط برنامه کمکی signalr.exe نیز وجود دارد؛ برای دریافت آن میتوان از طریق NuGet اقدام کرد (بسته Microsoft.AspNet.SignalR.Utils) که نهایتا در پوشه packages قرار خواهد گرفت. نحوه استفاده از آن نیز به صورت زیر است:
در این دستور ghp مخفف generate hub proxy است و نهایتا فایلی را به نام server.js تولید میکند.
ب) بدون استفاده از فایل proxy و به کمک روش late binding (انقیاد دیر هنگام)
برای کار با یک Hub از طریق jQuery مراحل ذیل باید طی شوند:
1) ارجاعی به Hub باید مشخص شود.
2) روالهای رخدادگردان تنظیم گردند.
3) اتصال به Hub برقرار گردد.
4) متدی فراخوانی شود.
در اینجا باید دقت داشت که امکانات Hub به صورت خواص
در سمت کلاینت جیکوئری، در دسترس خواهند بود. برای مثال:
و نامهای بکارگرفته شده در اینجا مطابق روشهای متداول نام گذاری در جاوا اسکریپت، camel case هستند.
خوب، تا اینجا فرض بر این است که یک پروژه خالی ASP.NET را آغاز و سپس فرمان نصب Microsoft.AspNet.SignalR.JS را نیز همانطور که عنوان شد، صادر کردهاید. در ادامه یک فایل ساده html را به نام chat.htm، به این پروژه جدید اضافه کنید (برای استفاده از کتابخانه جاوا اسکریپتی SignalR الزامی به استفاده از صفحات کامل پروژههای وب نیست).
کدهای آنرا به نحو فوق تغییر دهید.
توضیحات:
همانطور که ملاحظه میکنید ابتدا ارجاعاتی به jquery و jquery.signalR-1.0.1.min.js اضافه شدهاند. سپس نیاز است مسیر دقیق فایل پروکسی هاب خود را نیز مشخص کنیم. اینکار با تعریف مسیر signalr/hubs انجام شده است.
در ادامه توسط تنظیم connection.hub.logging سبب خواهیم شد تا اطلاعات بیشتری در javascript console مرورگر لاگ شود.
سپس ارجاعی به هاب تعریف شده، تعریف گردیده است. اگر از قسمت قبل به خاطر داشته باشید، توسط ویژگی HubName، نام chat را برگزیدیم. بنابراین connection.chat ذکر شده دقیقا به این هاب اشاره میکند.
سپس سطر chat.client.hello مقدار دهی شده است. متد hello، متدی dynamic و تعریف شده در سمت هاب برنامه است. به این ترتیب میتوان به پیامهای رسیده از طرف سرور گوش فرا داد. در اینجا، این پیامها، به li ایی با id مساوی messages اضافه میشوند.
سپس توسط فراخوانی متد connection.hub.start، فاز negotiation شروع میشود. در اینجا حتی میتوان نوع transport را نیز صریحا انتخاب کرد که نمونهای از آن را به صورت کامنت شده جهت آشنایی با نحوه تعریف آن مشاهده میکنید. مقادیر قابل استفاده در آن به شرح زیر هستند:
سپس به رویدادهای کلیک دکمه send گوش فرا داده و در این حین، اطلاعات TextBox ایی با id مساوی txtMsg را به متد SendMessage هاب خود ارسال میکنیم. همانطور که پیشتر نیز عنوان شد، در سمت کلاینت، تعریف متد SendMessage باید camel case باشد.
اکنون به صورت جداگانه یکبار برنامه hub را در مرورگر باز کنید. سپس بر روی فایل chat.htm کلیک راست کرده و گزینه مشاهده آن را در مرورگر نیز انتخاب نمائید (گزینه View in browser منوی کلیک راست).
خوب! پروژه کار نمیکند! برای اینکه مشکلات را بهتر بتوانید مشاهده کنید نیاز است به JavaScript Console مرورگر خود مراجعه نمائید. برای مثال در مرورگر کروم دکمه F12 را فشرده و برگه Console آنرا باز کنید. در اینجا اعلام میکند که فاز negotiation قابل انجام نیست؛ چون مسیر پیش فرضی را که انتخاب کرده است، همین مسیر پروژه دومی است که اضافه کردهایم (کلاینت ما در پروژه دوم قرار دارد و نه در همان پروژه اول هاب).
برای اینکه مسیر دقیق hub را در این حالت مشخص کنیم، سطر زیر را به ابتدای کدهای جاوا اسکریپتی فوق اضافه نمائید:
اکنون اگر مجدا سعی کنید، باز هم برنامه کار نمیکند و پیام میدهد که امکان دسترسی به این سرویس از خارج از دومین آن میسر نیست. برای اینکه این مجوز را صادر کنیم نیاز است تنظیمات مسیریابی پروژه هاب را به نحو ذیل ویرایش نمائیم:
با تنظیم EnableCrossDomain به true اینبار فازهای آغاز ارتباط با سرور برقرار میشوند:
مطابق این لاگها ابتدا فاز negotiation انجام میشود. سپس حالت long polling را به صورت خودکار انتخاب میکند.
در برگه شبکه، مطابق شکل فوق، امکان آنالیز اطلاعات رد و بدل شده مهیا است. برای مثال در حالتیکه سرور پیام دریافتی را به کلیه کلاینتها ارسال میکند، نام متد و نام هاب و سایر پارامترها در اطلاعات به فرمت JSON آن به خوبی قابل مشاهده هستند.
یک نکته:
اگر از ویندوز 8 (یعنی IIS8) و VS 2012 استفاده میکنید، برای استفاده از حالت Web socket، ابتدا فایل وب کانفیگ برنامه را باز کرده و در قسمت httpRunTime، مقدار ویژگی targetFramework را بر روی 4.5 تنظیم کنید. اینبار اگر مراحل negotiation را بررسی کنید در همان مرحله اول برقراری اتصال، از روش Web socket استفاده گردیده است.
تمرین 1
به پروژه ساده و ابتدایی فوق یک تکست باکس دیگر به نام Room را اضافه کنید؛ به همراه دکمه join. سپس نکات قسمت قبل را در مورد الحاق به یک گروه و سپس ارسال پیام به اعضای گروه را پیاده سازی نمائید. (تمام نکات آن با مطلب فوق پوشش داده شده است و در اینجا باید صرفا فراخوانی متدهای عمومی دیگری در سمت هاب، صورت گیرد)
تمرین 2
در انتهای قسمت دوم به نحوه ارسال پیام از یک هاب به هابی دیگر اشاره شد. این MonitorHub را ایجاد کرده و همچنین یک کلاینت جاوا اسکریپتی را نیز برای آن تهیه کنید تا بتوان اتصال و قطع اتصال کلیه کاربران سیستم را مانیتور و مشاهده کرد.
پیاده سازی کلاینت jQuery بدون استفاده از کلاس Proxy
در مثال قبل، از پروکسی پویای مهیای در آدرس signalr/hubs استفاده کردیم. در اینجا قصد داریم، بدون استفاده از آن نیز کار برپایی کلاینت را بررسی کنیم.
بنابراین یک فایل جدید html را مثلا به نام chat_np.html به پروژه دوم برنامه اضافه کنید. سپس محتویات آنرا به نحو زیر تغییر دهید:
در اینجا سطر مرتبط با تعریف مسیر اسکریپتهای پویای signalr/hubs را دیگر در ابتدای فایل مشاهده نمیکنید. کار تشکیل proxy اینبار از طریق کدنویسی صورت گرفته است. پس از ایجاد پروکسی، برای گوش فرا دادن به متدهای فراخوانی شده از طرف سرور از متد proxy.on و نام متد فراخوانی شده سمت سرور استفاده میکنیم و یا برای ارسال اطلاعات به سرور از متد proxy.invoke به همراه نام متد سمت سرور استفاده خواهد شد.
کلاینتهای دات نتی SignalR
تا کنون Solution ما حاوی یک پروژه Hub و یک پروژه وب کلاینت جیکوئری است. به همین Solution، یک پروژه کلاینت کنسول ویندوزی را نیز اضافه کنید.
سپس در خط فرمان پاور شل نوگت دستور زیر را صادر نمائید تا فایلهای مورد نیاز به پروژه کنسول اضافه شوند:
در اینجا نیز باید دقت داشت تا دستور بر روی default project صحیحی اجرا شود (حالت پیش فرض، اولین پروژه موجود در solution است).
پس از نصب آن اگر به پوشه packages مراجعه کنید، نگارشهای مختلف آنرا مخصوص سیلورلایت، دات نتهای 4 و 4.5، WinRT و ویندوز فون8 نیز میتوانید در پوشه Microsoft.AspNet.SignalR.Client ملاحظه نمائید. البته در ابتدای نصب، انتخاب نگارش مناسب، بر اساس نوع پروژه جاری به صورت خودکار صورت میگیرد.
مدل برنامه نویسی آن نیز بسیار شبیه است به حالت عدم استفاده از پروکسی در حین استفاده از jQuery که در قسمت قبل بررسی گردید و شامل این مراحل است:
1) یک وهله از شیء HubConnection را ایجاد کنید.
2) پروکسی مورد نیاز را جهت اتصال به Hub از طریق متد CreateProxy تهیه کنید.
3) رویدادگردانها را همانند نمونه کدهای جاوا اسکریپتی قسمت قبل، توسط متد On تعریف کنید.
4) به کمک متد Start، اتصال را آغاز نمائید.
5) متدها را به کمک متد Invoke فراخوانی نمائید.
نمونهای از این پیاده سازی را در کدهای فوق ملاحظه میکنید که از لحاظ طراحی آنچنان تفاوتی با نمونه ذهنی جاوا اسکریپتی ندارد.
نکته مهم
کلیه فراخوانیهایی که در اینجا ملاحظه میکنید غیرهمزمان هستند.
به همین جهت پس از متد Start، متد Wait ذکر شدهاست تا در این برنامه ساده، پس از برقراری کامل اتصال، کار invoke صورت گیرد و یا زمانیکه callback تعریف شده توسط متد chat.On فراخوانی میشود نیز این فراخوانی غیرهمزمان است و خصوصا اگر نیاز است رابط کاربری برنامه را در این بین به روز کنید باید به نکات به روز رسانی رابط کاربری از طریق یک ترد دیگر دقت داشت.
مصرف کنندگان یک Hub میتوانند انواع و اقسام برنامههای کلاینت مانند jQuery Clients و یا حتی یک برنامه کنسول ساده باشند و همچنین Hubهای دیگر نیز قابلیت استفاده از این امکانات Hubهای موجود را دارند. تیم SignalR امکان استفاده از Hubهای آنرا در برنامههای دات نت 4 به بعد، برنامههای WinRT، ویندوز فون 8، سیلورلایت 5، jQuery و همچنین برنامههای CPP نیز مهیا کردهاند. به علاوه گروههای مختلف نیز با توجه به سورس باز بودن این مجموعه، کلاینتهای iOS Native، iOS via Mono و Android via Mono را نیز به این لیست اضافه کردهاند.
بررسی کلاینتهای jQuery
با توجه به پروتکل مبتنی بر JSON سیگنالآر، استفاده از آن در کتابخانههای جاوا اسکریپتی همانند jQuery نیز به سادگی مهیا است. برای نصب آن نیاز است در کنسول پاور شل نوگت، دستور زیر را صادر کنید:
PM> Install-Package Microsoft.AspNet.SignalR.JS
با استفاده از افزونه SignalR jQuery، به دو طریق میتوان به یک Hub اتصال برقرار کرد:
الف) استفاده از فایل proxy تولید شده آن (این فایل، در زمان اجرای برنامه تولید میشود و یا امکان استفاده از آن به کمک ابزارهای کمکی نیز وجود دارد)
نمونهای از آنرا در قسمت قبل ملاحظه کردید؛ همان فایل تولید شده در مسیر /signalr/hubs برنامه. به نوعی به آن Service contract نیز گفته میشود (ارائه متادیتا و قراردادهای کار با یک سرویس Hub). این فایل همانطور که عنوان شد به صورت پویا در زمان اجرای برنامه ایجاد میشود.
امکان تولید آن توسط برنامه کمکی signalr.exe نیز وجود دارد؛ برای دریافت آن میتوان از طریق NuGet اقدام کرد (بسته Microsoft.AspNet.SignalR.Utils) که نهایتا در پوشه packages قرار خواهد گرفت. نحوه استفاده از آن نیز به صورت زیر است:
Signalr.exe ghp http://localhost/
ب) بدون استفاده از فایل proxy و به کمک روش late binding (انقیاد دیر هنگام)
برای کار با یک Hub از طریق jQuery مراحل ذیل باید طی شوند:
1) ارجاعی به Hub باید مشخص شود.
2) روالهای رخدادگردان تنظیم گردند.
3) اتصال به Hub برقرار گردد.
4) متدی فراخوانی شود.
در اینجا باید دقت داشت که امکانات Hub به صورت خواص
$.connection
$.connection.chatHub
خوب، تا اینجا فرض بر این است که یک پروژه خالی ASP.NET را آغاز و سپس فرمان نصب Microsoft.AspNet.SignalR.JS را نیز همانطور که عنوان شد، صادر کردهاید. در ادامه یک فایل ساده html را به نام chat.htm، به این پروژه جدید اضافه کنید (برای استفاده از کتابخانه جاوا اسکریپتی SignalR الزامی به استفاده از صفحات کامل پروژههای وب نیست).
<!DOCTYPE> <html> <head> <title></title> <script src="Scripts/jquery-1.6.4.min.js" type="text/javascript"></script> <script src="Scripts/jquery.signalR-1.0.1.min.js" type="text/javascript"></script> <script src="http://localhost:1072/signalr/hubs" type="text/javascript"></script> </head> <body> <div> <input id="txtMsg" type="text" /><input id="send" type="button" value="send msg" /> <ul id="messages"> </ul> </div> <script type="text/javascript"> $(function () { var chat; $.connection.hub.logging = true; //اطلاعات بیشتری را در جاوا اسکریپت کنسول مرورگر لاگ میکند chat = $.connection.chat; //این نام مستعار پیشتر توسط ویژگی نام هاب تنظیم شده است chat.client.hello = function (message) { //متدی که در اینجا تعریف شده دقیقا مطابق نام متد پویایی است که در هاب تعریف شده است //به این ترتیب سرور میتواند کلاینت را فراخوانی کند $("#messages").append("<li>" + message + "</li>"); }; $.connection.hub.start(/*{ transport: 'longPolling' }*/); // فاز اولیه ارتباط را آغاز میکند $("#send").click(function () { // Hub's `SendMessage` should be camel case here chat.server.sendMessage($("#txtMsg").val()); }); }); </script> </body> </html>
توضیحات:
همانطور که ملاحظه میکنید ابتدا ارجاعاتی به jquery و jquery.signalR-1.0.1.min.js اضافه شدهاند. سپس نیاز است مسیر دقیق فایل پروکسی هاب خود را نیز مشخص کنیم. اینکار با تعریف مسیر signalr/hubs انجام شده است.
<script src="http://localhost:1072/signalr/hubs" type="text/javascript"></script>
سپس ارجاعی به هاب تعریف شده، تعریف گردیده است. اگر از قسمت قبل به خاطر داشته باشید، توسط ویژگی HubName، نام chat را برگزیدیم. بنابراین connection.chat ذکر شده دقیقا به این هاب اشاره میکند.
سپس سطر chat.client.hello مقدار دهی شده است. متد hello، متدی dynamic و تعریف شده در سمت هاب برنامه است. به این ترتیب میتوان به پیامهای رسیده از طرف سرور گوش فرا داد. در اینجا، این پیامها، به li ایی با id مساوی messages اضافه میشوند.
سپس توسط فراخوانی متد connection.hub.start، فاز negotiation شروع میشود. در اینجا حتی میتوان نوع transport را نیز صریحا انتخاب کرد که نمونهای از آن را به صورت کامنت شده جهت آشنایی با نحوه تعریف آن مشاهده میکنید. مقادیر قابل استفاده در آن به شرح زیر هستند:
- webSockets - forverFrame - serverSentEvents - longPolling
اکنون به صورت جداگانه یکبار برنامه hub را در مرورگر باز کنید. سپس بر روی فایل chat.htm کلیک راست کرده و گزینه مشاهده آن را در مرورگر نیز انتخاب نمائید (گزینه View in browser منوی کلیک راست).
خوب! پروژه کار نمیکند! برای اینکه مشکلات را بهتر بتوانید مشاهده کنید نیاز است به JavaScript Console مرورگر خود مراجعه نمائید. برای مثال در مرورگر کروم دکمه F12 را فشرده و برگه Console آنرا باز کنید. در اینجا اعلام میکند که فاز negotiation قابل انجام نیست؛ چون مسیر پیش فرضی را که انتخاب کرده است، همین مسیر پروژه دومی است که اضافه کردهایم (کلاینت ما در پروژه دوم قرار دارد و نه در همان پروژه اول هاب).
برای اینکه مسیر دقیق hub را در این حالت مشخص کنیم، سطر زیر را به ابتدای کدهای جاوا اسکریپتی فوق اضافه نمائید:
$.connection.hub.url = 'http://localhost:1072/signalr'; //چون در یک پروژه دیگر قرار داریم
using System; using System.Web; using System.Web.Routing; using Microsoft.AspNet.SignalR; namespace SignalR02 { public class Global : HttpApplication { protected void Application_Start(object sender, EventArgs e) { // Register the default hubs route: ~/signalr RouteTable.Routes.MapHubs(new HubConfiguration { EnableCrossDomain = true }); } } }
SignalR: Auto detected cross domain url. jquery.signalR-1.0.1.min.js:10 SignalR: Negotiating with 'http://localhost:1072/signalr/negotiate'. jquery.signalR-1.0.1.min.js:10 SignalR: SignalR: Initializing long polling connection with server. jquery.signalR-1.0.1.min.js:10 SignalR: Attempting to connect to 'http://localhost:1072/signalr/connect?transport=longPolling&connectionToken…NRh72omzsPkKqhKw2&connectionData=%5B%7B%22name%22%3A%22chat%22%7D%5D&tid=3' using longPolling. jquery.signalR-1.0.1.min.js:10 SignalR: Longpolling connected jquery.signalR-1.0.1.min.js:10
در برگه شبکه، مطابق شکل فوق، امکان آنالیز اطلاعات رد و بدل شده مهیا است. برای مثال در حالتیکه سرور پیام دریافتی را به کلیه کلاینتها ارسال میکند، نام متد و نام هاب و سایر پارامترها در اطلاعات به فرمت JSON آن به خوبی قابل مشاهده هستند.
یک نکته:
اگر از ویندوز 8 (یعنی IIS8) و VS 2012 استفاده میکنید، برای استفاده از حالت Web socket، ابتدا فایل وب کانفیگ برنامه را باز کرده و در قسمت httpRunTime، مقدار ویژگی targetFramework را بر روی 4.5 تنظیم کنید. اینبار اگر مراحل negotiation را بررسی کنید در همان مرحله اول برقراری اتصال، از روش Web socket استفاده گردیده است.
تمرین 1
به پروژه ساده و ابتدایی فوق یک تکست باکس دیگر به نام Room را اضافه کنید؛ به همراه دکمه join. سپس نکات قسمت قبل را در مورد الحاق به یک گروه و سپس ارسال پیام به اعضای گروه را پیاده سازی نمائید. (تمام نکات آن با مطلب فوق پوشش داده شده است و در اینجا باید صرفا فراخوانی متدهای عمومی دیگری در سمت هاب، صورت گیرد)
تمرین 2
در انتهای قسمت دوم به نحوه ارسال پیام از یک هاب به هابی دیگر اشاره شد. این MonitorHub را ایجاد کرده و همچنین یک کلاینت جاوا اسکریپتی را نیز برای آن تهیه کنید تا بتوان اتصال و قطع اتصال کلیه کاربران سیستم را مانیتور و مشاهده کرد.
پیاده سازی کلاینت jQuery بدون استفاده از کلاس Proxy
در مثال قبل، از پروکسی پویای مهیای در آدرس signalr/hubs استفاده کردیم. در اینجا قصد داریم، بدون استفاده از آن نیز کار برپایی کلاینت را بررسی کنیم.
بنابراین یک فایل جدید html را مثلا به نام chat_np.html به پروژه دوم برنامه اضافه کنید. سپس محتویات آنرا به نحو زیر تغییر دهید:
<!DOCTYPE> <html> <head> <title></title> <script src="Scripts/jquery-1.6.4.min.js" type="text/javascript"></script> <script src="Scripts/jquery.signalR-1.0.1.min.js" type="text/javascript"></script> </head> <body> <div> <input id="txtMsg" type="text" /><input id="send" type="button" value="send msg" /> <ul id="messages"> </ul> </div> <script type="text/javascript"> $(function () { $.connection.hub.logging = true; //اطلاعات بیشتری را در جاوا اسکریپت کنسول مرورگر لاگ میکند var connection = $.hubConnection(); connection.url = 'http://localhost:1072/signalr'; //چون در یک پروژه دیگر قرار داریم var proxy = connection.createHubProxy('chat'); proxy.on('hello', function (message) { //متدی که در اینجا تعریف شده دقیقا مطابق نام متد پویایی است که در هاب تعریف شده است //به این ترتیب سرور میتواند کلاینت را فراخوانی کند $("#messages").append("<li>" + message + "</li>"); }); $("#send").click(function () { // Hub's `SendMessage` should be camel case here proxy.invoke('sendMessage', $("#txtMsg").val()); }); connection.start(); }); </script> </body> </html>
کلاینتهای دات نتی SignalR
تا کنون Solution ما حاوی یک پروژه Hub و یک پروژه وب کلاینت جیکوئری است. به همین Solution، یک پروژه کلاینت کنسول ویندوزی را نیز اضافه کنید.
سپس در خط فرمان پاور شل نوگت دستور زیر را صادر نمائید تا فایلهای مورد نیاز به پروژه کنسول اضافه شوند:
PM> Install-Package Microsoft.AspNet.SignalR.Client
پس از نصب آن اگر به پوشه packages مراجعه کنید، نگارشهای مختلف آنرا مخصوص سیلورلایت، دات نتهای 4 و 4.5، WinRT و ویندوز فون8 نیز میتوانید در پوشه Microsoft.AspNet.SignalR.Client ملاحظه نمائید. البته در ابتدای نصب، انتخاب نگارش مناسب، بر اساس نوع پروژه جاری به صورت خودکار صورت میگیرد.
مدل برنامه نویسی آن نیز بسیار شبیه است به حالت عدم استفاده از پروکسی در حین استفاده از jQuery که در قسمت قبل بررسی گردید و شامل این مراحل است:
1) یک وهله از شیء HubConnection را ایجاد کنید.
2) پروکسی مورد نیاز را جهت اتصال به Hub از طریق متد CreateProxy تهیه کنید.
3) رویدادگردانها را همانند نمونه کدهای جاوا اسکریپتی قسمت قبل، توسط متد On تعریف کنید.
4) به کمک متد Start، اتصال را آغاز نمائید.
5) متدها را به کمک متد Invoke فراخوانی نمائید.
using System; using Microsoft.AspNet.SignalR.Client.Hubs; namespace SignalR02.WinClient { class Program { static void Main(string[] args) { var hubConnection = new HubConnection(url: "http://localhost:1072/signalr"); var chat = hubConnection.CreateHubProxy(hubName: "chat"); chat.On<string>("hello", msg => { Console.WriteLine(msg); }); hubConnection.Start().Wait(); chat.Invoke<string>("sendMessage", "Hello!"); Console.WriteLine("Press a key to terminate the client..."); Console.Read(); } } }
نکته مهم
کلیه فراخوانیهایی که در اینجا ملاحظه میکنید غیرهمزمان هستند.
به همین جهت پس از متد Start، متد Wait ذکر شدهاست تا در این برنامه ساده، پس از برقراری کامل اتصال، کار invoke صورت گیرد و یا زمانیکه callback تعریف شده توسط متد chat.On فراخوانی میشود نیز این فراخوانی غیرهمزمان است و خصوصا اگر نیاز است رابط کاربری برنامه را در این بین به روز کنید باید به نکات به روز رسانی رابط کاربری از طریق یک ترد دیگر دقت داشت.
اگر به مرورگرها دقت کرده باشید، امکان نمایش SSL Server Certificate یک سایت استفاده کننده از پروتکل HTTPS را دارند. برای مثال در فایرفاکس اگر به خواص یک صفحه مراجعه کنیم، در برگه امنیت آن، امکان مشاهده جزئیات مجوز SSL سایت جاری فراهم است:
سؤال: چگونه میتوان این مجوزها را با کدنویسی دریافت یا تعیین اعتبار کرد؟
قطعه کد زیر، نحوه دریافت مجوز SSL یک سایت را نمایش میدهد:
ممکن است مجوز یک سایت معتبر نباشد. کلاس WebRequest در حین مواجه شدن با یک چنین سایتهایی، یک WebException را صادر میکند. از این جهت که میخواهیم حتما این مجوز را دریافت کنیم، بنابراین در ابتدای کار، ServerCertificateValidation را غیرفعال میکنیم.
سپس یک درخواست ساده را به آدرس سرور مورد نظر ارسال میکنیم. پس از پایان درخواست، خاصیت request.ServicePoint.Certificate با مجوز SSL یک سایت مقدار دهی شده است. در ادامه نحوه ذخیره سازی این مجوز را با فرمت cer مشاهده میکنید.
سؤال: چگونه میتوان این مجوزها را با کدنویسی دریافت یا تعیین اعتبار کرد؟
قطعه کد زیر، نحوه دریافت مجوز SSL یک سایت را نمایش میدهد:
using System; using System.Diagnostics; using System.IO; using System.Net; using System.Security.Cryptography.X509Certificates; namespace DownloadCerts { class Program { static void Main(string[] args) { // صرفنظر از خطاهای احتمالی مجوز ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; var url = "https://pdfreport.codeplex.com"; var request = WebRequest.Create(url) as HttpWebRequest; request.Method = WebRequestMethods.Http.Head; using (var response = request.GetResponse()) { /* در اینجا مجوز، در صورت وجود دریافت شده */ } if (request.ServicePoint.Certificate == null) return; // ذخیره سازی مجوز در فایل var cert = new X509Certificate2(request.ServicePoint.Certificate); Console.WriteLine("Expiration Date: {0}", cert.GetExpirationDateString()); var data = cert.Export(X509ContentType.Cert); File.WriteAllBytes("site.cer", data); Process.Start(Environment.CurrentDirectory); } } }
سپس یک درخواست ساده را به آدرس سرور مورد نظر ارسال میکنیم. پس از پایان درخواست، خاصیت request.ServicePoint.Certificate با مجوز SSL یک سایت مقدار دهی شده است. در ادامه نحوه ذخیره سازی این مجوز را با فرمت cer مشاهده میکنید.
مطالب دورهها
عیب یابی و دیباگ برنامههای SignalR
1) برنامه SignalR در IE کار نمیکند.
پردازشگر json، در نگارشهای اخیر IE به آن اضافه شده است. برای رفع این مشکل در نگارشهای قدیمی، نیاز است از اسکریپت کمکی http://nuget.org/List/Packages/json2 استفاده نمائید. همچنین مرورگر IE را نیز باید وادار ساخت تا بر اساس آخرین موتور پردازشی خود کار کند:
2) هنگام فراخوانی مسیر signalr/hubs پیغام 404 (یافت نشد) دریافت میشود.
برای رفع این مشکل ابتدا اطمینان حاصل کنید که تنظیمات مسیریابی تعریف شده در فایل global.asax.cs موجود هستند.
در ادامه اطمینان حاصل نمائید مسیر اسکریپتهای signalr/hubs به درستی تعریف شدهاند:
برای مثال در برنامههای MVC و وب فرمها تعریف صحیح باید به شکل زیر باشد:
همچنین وجود تنظیمات ذیل را در فایل وب کانفیگ برنامه نیز بررسی کنید:
3) متدهای سمت کلاینت من فراخوانی نمیشوند.
بهترین راه برای مشاهده ریز جرئیات خطاها، ذکر سطر ذیل در کدهای سمت کلاینت جاوا اسکریپتی برنامه است:
و سپس مراجعه به کنسول جاوا اسکریپت مرورگر برای بررسی خطاهای لاگ شده.
4) خطای «Connection must be started before data can be sent» را دریافت میکنم.
همانطور که در قسمت قبل عنوان شد، کلیه فراخوانیهای SignalR از نوع غیرهمزمان هستند. بنابراین باید با استفاده از callback و زمان فراخوانی آنها که عموما پس از برقراری اتصال رخ میدهد، نسبت به انجام امور دلخواه اقدام کرد.
همانطور که در این مثال مشاهده میکنید، سطر proxy.invoke در یک callback فراخوانی شده است و نه بلافاصله در سطری پس از connection.start. هر زمان که اتصال به نحو موفقیت آمیزی برقرار شد، آنگاه متد subscribe در سمت سرور فراخوانی میگردد.
در حالت استفاده بدون پروکسی نیز چنین callbackهایی قابل تعریف هستند:
5) بعد از 10 اتصال به IIS، برنامه متوقف میشود.
این مورد، محدودیت ذاتی IIS 7 نصب شده بر روی ویندوز 7 است. بهتر است از یک IIS کامل موجود در ویندوزهای سرور استفاده کنید. در این سرورها عدد پیش فرض تنظیم شده 5000 اتصال است که در صورت نیاز با استفاده از دستور زیر قابل تغییر است:
به علاوه ASP.NET نیز محدودیت 5000 اتصال به ازای هر CPU را دارد. برای تغییر آن باید به مسیر ذیل مراجعه
و سپس مقدار maxConcurrentRequestsPerCPU را تنظیم کرد:
به علاوه ASP.NET پس از رد شدن از حد maxConcurrentRequestsPerCPU، درخواستها را در صف قرار میدهد. این مورد نیز قابل تنظیم است. ابتدا به مسیر ذیل مراجعه کرده
و سپس در صورت نیاز و لزوم، مقدار requestQueueLimit را تغییر دهید:
پردازشگر json، در نگارشهای اخیر IE به آن اضافه شده است. برای رفع این مشکل در نگارشهای قدیمی، نیاز است از اسکریپت کمکی http://nuget.org/List/Packages/json2 استفاده نمائید. همچنین مرورگر IE را نیز باید وادار ساخت تا بر اساس آخرین موتور پردازشی خود کار کند:
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
2) هنگام فراخوانی مسیر signalr/hubs پیغام 404 (یافت نشد) دریافت میشود.
برای رفع این مشکل ابتدا اطمینان حاصل کنید که تنظیمات مسیریابی تعریف شده در فایل global.asax.cs موجود هستند.
در ادامه اطمینان حاصل نمائید مسیر اسکریپتهای signalr/hubs به درستی تعریف شدهاند:
<script type="text/javascript" src="/signalr/hubs"></script>
MVC: <script type="text/javascript" src="@Url.Content("~/signalr/hubs")"></script> Web forms: <script type="text/javascript" src='<%= ResolveClientUrl("~/signalr/hubs") %>'></script>
<configuration> <system.webServer> <modules runAllManagedModulesForAllRequests="true"> </modules> </system.webServer> </configuration>
3) متدهای سمت کلاینت من فراخوانی نمیشوند.
بهترین راه برای مشاهده ریز جرئیات خطاها، ذکر سطر ذیل در کدهای سمت کلاینت جاوا اسکریپتی برنامه است:
$.connection.hub.logging = true;
4) خطای «Connection must be started before data can be sent» را دریافت میکنم.
همانطور که در قسمت قبل عنوان شد، کلیه فراخوانیهای SignalR از نوع غیرهمزمان هستند. بنابراین باید با استفاده از callback و زمان فراخوانی آنها که عموما پس از برقراری اتصال رخ میدهد، نسبت به انجام امور دلخواه اقدام کرد.
var connection = $.hubConnection('http://localhost:8081/'); proxy = connection.createProxy('collectionhub') connection.start() .done(function () { proxy.invoke('subscribe', 'Product'); $('#messages').append('<li>invoked subscribe</li>'); }) .fail(function () { alert("Could not Connect!"); });
در حالت استفاده بدون پروکسی نیز چنین callbackهایی قابل تعریف هستند:
$.connection.hub.start() .done(function() { myHub.server.SomeFunction(SomeParam) //e.g. a login or init .done(connectionReady); }) .fail(function() { alert("Could not Connect!"); });
5) بعد از 10 اتصال به IIS، برنامه متوقف میشود.
این مورد، محدودیت ذاتی IIS 7 نصب شده بر روی ویندوز 7 است. بهتر است از یک IIS کامل موجود در ویندوزهای سرور استفاده کنید. در این سرورها عدد پیش فرض تنظیم شده 5000 اتصال است که در صورت نیاز با استفاده از دستور زیر قابل تغییر است:
appcmd.exe set config /section:system.webserver/serverRuntime /appConcurrentRequestLimit:100000
%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet.config
<?xml version="1.0" encoding="UTF-8" ?> <configuration> <runtime> <legacyUnhandledExceptionPolicy enabled="false" /> <legacyImpersonationPolicy enabled="true"/> <alwaysFlowImpersonationPolicy enabled="false"/> <SymbolReadingPolicy enabled="1" /> <shadowCopyVerifyByTimestamp enabled="true"/> </runtime> <startup useLegacyV2RuntimeActivationPolicy="true" /> <system.web> <applicationPool maxConcurrentRequestsPerCPU="20000" /> </system.web> </configuration>
%windir%\Microsoft.NET\Framework\v4.0.30319\Config\machine.config
<processModel autoConfig="false" requestQueueLimit="250000" />
اشتراکها
کتابخانهی farsidate.js
«... با استفاده از این افزونه و شی ساخته شده از تابع سازنده Date اصلی جاوا اسکریپت میتوانید، تبدیلات زنجیرهای وار تقویم جلالی و گریگوریان را انجام دهید.
تمام فرمت تاریخ ارسالی و دریافتی از سمت سرور بر مبنای گریگوریان است، و از متد اعتبار سنجی تقویم گریگوریان کتابخانههای موجود سمت سرور میتوانید استفاده کنید و فقط در سمت کلاینت به جلالی نمایش دهید...»
اگر بخواهیم کلاس FluentValidation را بر اساس نوع TrackingState یک موجودیت، Ruleهای متفاوتی را پیاده سازی کنیم، و یکسری Ruleها را در حالتهای مختلف فعال / غیرفعال کنیم، ارث بری از MasterModel این Property را به همراه نخواهد داشت. چه راه حلی پیشنهاد میکنید؟ لطفا به همراه یک مثال بیان کنید.
و آیا این اعتبار سنجی در برنامههای SPA بصورت Remote Validation قابل پیاده سازی است یا حتما نیاز به ارسال مدل به اکشن مربوطه جهت بررسی اعتبارسنجها میباشد؟
سلام حقیقت من شخصا اعتقادی به استفاده از Windows-authentication برای اعتبار سنجی نداشتم ولی پروژه ای الان در دست دارم که ارتباط زیادی با اکتیو دایرکتوری داره.. به همین دلیل میخواستم بدونم:
بخش دسترسیهای کاربر رو هم میشه سمت اکتیودایرکتوری پیاده سازی کرد و برنامه از اون اطلاعات استفاده کنه یا چنین چیزی در Windows-authentication و اکتیودایرکتوری پیشبینی نشده. اگر قابل پیاده سازی بود ممنون میشم منبع معرفی کنید.
مراجعه کنید به مطلب «اعتبار سنجی ورودیهای کاربر در Kendo UI». در انتهای
مطلب در مورد «اعتبارسنجی سفارشی در DataSource»
بحث شدهاست. Kendo UI Grid هم اطلاعات اعتبارسنجی فیلدهای خودش را از data source دریافت میکند و ... اصول طراحی اعتبارسنجی آن، هیچ تفاوتی با نکتهی عنوان شده ندارد (یک custom rule سفارشی را به نام remote، دقیقا مانند همین مثال میتوانید اضافه کنید).