متدی برای بررسی صحت کد ملی وارد شده
Install-Package Microsoft.AspNetCore.Mvc.Versioning
public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddApiVersioning(); // ... }
services.AddApiVersioning(opt => { opt.AssumeDefaultVersionWhenUnspecified = true; opt.DefaultApiVersion = new ApiVersion(1, 0); });
- api/foo?api-version=1.0/
opt.DefaultApiVersion = new ApiVersion(new DateTime(2018, 10, 22));
- api/foo?api-version=2018-10-22/
URL Path Segment Versioning
[Route("api/v{version:apiVersion}/[controller]")] public class FooController : ControllerBase { public ActionResult<IEnumerable<string>> Get() { return new[] { "value1", "value2" }; } }
public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddApiVersioning(opt => opt.ApiVersionReader = new HeaderApiVersionReader("api-version")); }
Deprecating
[ApiVersion("2")] [ApiVersion("1", Deprecated = true)] [Route("api/v{version:apiVersion}/[controller]")] public class FooController : ControllerBase { [HttpGet] public string Get() => "I'm deprecated, Bye bye :("; [HttpGet, MapToApiVersion("2.0")] public string GetV2() => "Hello world ! :D"; }
services.AddApiVersioning(opt => { opt.DefaultApiVersion = new ApiVersion(1, 0); opt.AssumeDefaultVersionWhenUnspecified = true; opt.ReportApiVersions = true; });
Ignoring Versioning
[ApiVersionNeutral] [Route("api/[controller]")] public class BarController : ControllerBase { public string Get() => HttpContext.GetRequestedApiVersion().ToString(); }
مطلب تکمیلی:
namespace TestVersioning.Controllers.V1 { [ApiVersion("1", Deprecated = true)] [Route("api/v{version:apiVersion}/[controller]")] public class FooController : ControllerBase { public string Get() => "I'm deprecated, Bye bye :("; } } namespace TestVersioning.Controllers.V2 { [ApiVersion("2")] [Route("api/v{version:apiVersion}/[controller]")] public class FooController : ControllerBase { public string GetV2() => "Hello world ! :D"; } }
مزیت استفاده از یوزر کنترلها، ماژولار کردن برنامه است. برای مثال اگر صفحه جاری شما قرار است از چهار قسمت اخبار، منوی پویا ، سخن روز و آمار کاربران تشکیل شود، میتوان هر کدام را توسط یک یوزر کنترل پیاده سازی کرده و سپس صفحه اصلی را از کنار هم قرار دادن این یوزر کنترلها تهیه نمود.
با این توضیحات اکنون میخواهیم یک یوزکنترل ASP.Net را توسط jQuery Ajax بارگذاری کرده و نمایش دهیم. حداقل دو مورد کاربرد را میتوان برای آن متصور شد:
الف) در اولین باری که یک صفحه در حال بارگذاری است، قسمتهای مختلف آنرا بتوان از یوزر کنترلهای مختلف خواند و تا زمان بارگذاری کامل هر کدام، یک عبارت لطفا منتظر بمانید را نمایش داد. نمونهی آنرا شاید در بعضی از CMS های جدید دیده باشید. صفحه به سرعت بارگذاری میشود. در حالیکه مشغول مرور صفحه جاری هستید، قسمتهای مختلف صفحه پدیدار میشوند.
ب) بارگذاری یک قسمت دلخواه صفحه بر اساس درخواست کاربر. مثلا کلیک بر روی یک دکمه و امثال آن.
روش کلی کار:
1) تهیه یک متد وب سرویس که یوزر کنترل را بر روی سرور اجرا کرده و حاصل را تبدیل به یک رشته کند.
2) استفاده از متد Ajax جیکوئری برای فراخوانی این متد وب سرویس و افزودن رشته دریافت شده به صفحه.
بدیهی است زمانیکه متد Ajax فراخوانی میشود میتوان عبارت یا تصویر منتظر بمانید را نمایش داد و پس از پایان کار این متد، عبارت (یا تصویر) را مخفی نمود.
پیاده سازی:
قسمت تبدیل یک یوزر کنترل به رشته را قبلا در مقاله "تهیه قالب برای ایمیلهای ارسالی یک برنامه ASP.Net" مشاهده کردهاید. در اینجا برای استفاده از این متد در یک وب سرویس نیاز به کمی تغییر وجود داشت (KeyValuePair ها درست سریالایز نمیشوند) که نتیجه نهایی به صورت زیر است. یک فایل Ajax.asmx را به برنامه اضافه کرده و سپس در صفحه Ajax.asmx.cs کد آن به صورت زیر میتواند باشد:
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Script.Services;
using System.Web.Services;
using System.Web.UI;
using System.Web.UI.HtmlControls;
namespace AjaxTest
{
public class KeyVal
{
public string Key { set; get; }
public object Value { set; get; }
}
/// <summary>
/// Summary description for Ajax
/// </summary>
[ScriptService]
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class Ajax : WebService
{
/// <summary>
/// Removes Form tags using Regular Expression
/// </summary>
private static string cleanHtml(string html)
{
return Regex.Replace(html, @"<[/]?(form)[^>]*?>", string.Empty, RegexOptions.IgnoreCase);
}
/// <summary>
/// تبدیل یک یوزر کنترل به معادل اچ تی ام ال آن
/// </summary>
/// <param name="path">مسیر یوزر کنترل</param>
/// <param name="properties">لیست خواص به همراه مقادیر مورد نظر</param>
/// <returns></returns>
/// <exception cref="NotImplementedException"><c>NotImplementedException</c>.</exception>
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string RenderUserControl(string path,
List<KeyVal> properties)
{
Page pageHolder = new Page();
UserControl viewControl =
(UserControl)pageHolder.LoadControl(path);
viewControl.EnableViewState = false;
Type viewControlType = viewControl.GetType();
if (properties != null)
foreach (var pair in properties)
{
if (pair.Key != null)
{
PropertyInfo property =
viewControlType.GetProperty(pair.Key);
if (property != null)
{
if (pair.Value != null) property.SetValue(viewControl, pair.Value, null);
}
else
{
throw new NotImplementedException(string.Format(
"UserControl: {0} does not have a public {1} property.",
path, pair.Key));
}
}
}
//Form control is mandatory on page control to process User Controls
HtmlForm form = new HtmlForm();
//Add user control to the form
form.Controls.Add(viewControl);
//Add form to the page
pageHolder.Controls.Add(form);
//Write the control Html to text writer
StringWriter textWriter = new StringWriter();
//execute page on server
HttpContext.Current.Server.Execute(pageHolder, textWriter, false);
// Clean up code and return html
return cleanHtml(textWriter.ToString());
}
}
}
چند نکته:
الف) وب کانفیگ برنامه ASP.Net شما اگر با VS 2008 ایجاد شده باشد مداخل لازم را برای استفاده از این وب سرویس توسط jQuery Ajax دارد در غیر اینصورت موفق به استفاده از آن نخواهید شد.
ب) هنگام بازگرداندن این اطلاعات با فرمت json = ResponseFormat.Json جهت استفاده در jQuery Ajax ، گاهی از اوقات بسته به حجم بازگردانده شده ممکن است خطایی حاصل شده و عملیات متوقف شد. این طول پیش فرض را (maxJsonLength) در وب کانفیگ به صورت زیر تنظیم کنید تا مشکل حل شود:
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization maxJsonLength="10000000"></jsonSerialization>
</webServices>
</scripting>
</system.web.extensions>
برای پیاده سازی قسمت Ajax آن برای اینکه کار کمی تمیزتر و با قابلیت استفاده مجدد شود یک پلاگین تهیه شده (فایلی با نام jquery.advloaduc.js) که سورس آن به صورت زیر است:
$.fn.advloaduc = function(options) {
var defaults = {
webServiceName: 'Ajax.asmx', //نام فایل وب سرویس ما
renderUCMethod: 'RenderUserControl', //متد وب سرویس
ucMethodJsonParams: '{path:\'\'}',//پارامترهایی که قرار است پاس شوند
completeHandler: null //پس از پایان کار وب سرویس این متد جاوا اسکریپتی فراخوانی میشود
};
var options = $.extend(defaults, options);
return this.each(function() {
var obj = $(this);
obj.prepend("<div align='center'> لطفا اندکی تامل بفرمائید... <img src=\"images/loading.gif\"/></div>");
$.ajax({
type: "POST",
url: options.webServiceName + "/" + options.renderUCMethod,
data: options.ucMethodJsonParams,
contentType: "application/json; charset=utf-8",
dataType: "json",
success:
function(msg) {
obj.html(msg.d);
// if specified make callback and pass element
if (options.completeHandler)
options.completeHandler(this);
},
error:
function(XMLHttpRequest, textStatus, errorThrown) {
obj.html("امکان اتصال به سرور در این لحظه مقدور نیست. لطفا مجددا سعی کنید.");
}
});
});
};
عمده کاری که در این پلاگین صورت میگیرد فراخوانی متد Ajax جیکوئری است. سپس به متد وب سرویس ما (که در اینجا نام آن به صورت پارامتر نیز قابل دریافت است)، پارامترهای لازم پاس شده و سپس نتیجه حاصل به یک شیء در صفحه اضافه میشود.
completeHandler آن اختیاری است و پس از پایان کار متد اجکس فراخوانی میشود. در صورتیکه به آن نیازی نداشتید یا مقدار آن را null قرار دهید یا اصلا آنرا ذکر نکنید.
مثالی در مورد استفاده از این وب سرویس و همچنین پلاگین جیکوئری نوشته شده:
الف) یوزر کنترل ساده زیر را به پروژه اضافه کنید:
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="part1.ascx.cs" Inherits="TestJQueryAjax.part1" %>
<asp:Label runat="server" ID="lblData" ></asp:Label>
سپس کد آنرا به صورت زیر تغییر دهید:
using System;
using System.Threading;
namespace TestJQueryAjax
{
public partial class part1 : System.Web.UI.UserControl
{
public string Text1 { set; get; }
public string Text2 { set; get; }
protected void Page_Load(object sender, EventArgs e)
{
Thread.Sleep(3000);
if (!string.IsNullOrEmpty(Text1) && !string.IsNullOrEmpty(Text2))
lblData.Text = Text1 + "<br/>" + Text2;
}
}
}
عمدا یک sleep سه ثانیهای در اینجا در نظر گرفته شده تا اثر آنرا بهتر بتوان مشاهده کرد.
ب) اکنون کد مربوط به صفحهای که قرار است این یوزر کنترل را به صورت غیرهمزمان بارگذاری کند به صورت زیر خواهد بود (مهمترین قسمت آن نحوه تشکیل پارامترها و مقدار دهی خواص یوزر کنترل است):
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="TestJQueryAjax._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script src="js/jquery.js" type="text/javascript"></script>
<script src="js/jquery.advloaduc.js" type="text/javascript"></script>
<script src="js/json2.js" type="text/javascript"></script>
<script type="text/javascript">
function showAlert() {
alert('finished!');
}
//تشکیل پارامترهای متد وب سرویس جهت ارسال به آن
var fileName = 'part1.ascx';
var props = [{ 'Key': 'Text1', 'Value': 'سطر یک' }, { 'Key': 'Text2', 'Value': 'سطر 2'}];
var jsonText = JSON.stringify({ path: fileName, properties: props });
$(document).ready(function() {
$("#loadMyUc").advloaduc({
webServiceName: 'Ajax.asmx',
renderUCMethod: 'RenderUserControl',
ucMethodJsonParams: jsonText,
completeHandler: showAlert
});
});
</script>
</head>
<body>
<form id="form1" runat="server">
<div id="loadMyUc">
</div>
</form>
</body>
</html>
برای ارسال صحیح و امن اطلاعات json به سرور، از اسکریپت استاندارد json2.js استفاده شد.
ابزار دیباگ:
بهترین ابزار برای دیباگ این نوع اسکریپتها استفاده از افزونه فایرباگ فایرفاکس است. برای مثال مطابق تصویر زیر، یوزر کنترلی فراخوانی شده است که در سرور وجود ندارد:
دریافت مثال فوق
تولید اعداد تصادفی در جاوا اسکریپت
ایجاد یک اسمبلی جدید توسط Reflection.Emit
using System; using System.Reflection; using System.Reflection.Emit; namespace FastReflectionTests { class Program { static void Main(string[] args) { var name = "HelloWorld.exe"; var assemblyName = new AssemblyName(name); // ایجاد یک اسمبلی جدید با قابلیت ذخیره سازی آن var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly( name: assemblyName, access: AssemblyBuilderAccess.RunAndSave); // افزودن یک ماژول به اسمبلی var moduleBuilder = assemblyBuilder.DefineDynamicModule(name); // تعریف یک کلاس در این ماژول var programmClass = moduleBuilder.DefineType("Program", TypeAttributes.Public); // افزودن یک متد به این کلاس // این متد خروجی ندارد اما ورودی آن شبیه به متد اصلی یک برنامه کنسول است var mainMethod = programmClass.DefineMethod(name: "Main", attributes: MethodAttributes.Public | MethodAttributes.Static, returnType: null, parameterTypes: new Type[] { typeof(string[]) }); // تعیین بدنه متد اصلی برنامه var il = mainMethod.GetILGenerator(); il.Emit(OpCodes.Ldstr, "Hello World!"); il.Emit(OpCodes.Call, (typeof(Console)).GetMethod("WriteLine", new Type[] { typeof(string) })); il.Emit(OpCodes.Call, (typeof(Console)).GetMethod("ReadKey", new Type[0])); il.Emit(OpCodes.Pop); il.Emit(OpCodes.Ret); // تکمیل کار ایجاد نوع جدید programmClass.CreateType(); // تعیین نقطه شروع فایل اجرایی برنامه کنسول تهیه شده assemblyBuilder.SetEntryPoint(((Type)programmClass).GetMethod("Main")); // ذخیره سازی این اسمبلی بر روی دیسک سخت assemblyBuilder.Save(name); } } }
using System; public class Program { public static void Main(string[] array) { Console.WriteLine("Hello World!"); Console.ReadKey(); } }
استفاده از محیط گرافیکی IIS جهت لیست کردن، اضافه و حذف ماژولها
به بخش modules درIIS بروید. در پنل سمت راست همه امکانات جهت افزودن و ویرایش و حذف وجود دارند:
روش معرفی ماژول در خط فرمان با استفاده از دستور Appcmd
Appcmd.exe install module /name:MODULE_NAME /image:PATH_TO_DLL
قسمت name که نام ماژول است و قسمت image هم مسیر قرار گرفتن فایل dll هست.
برای نمونه:
%windir%\system32\inetsrv\appcmd.exe install module /name:DefaultDocumentModule /image:%windir%\system32\inetsrv\defdoc.dll
در صورتیکه ماژولی که قبلا افزوده شده باشد را بخواهید اضافه کنید، خطای زیر را دریافت خواهید کرد:
ERROR ( message:Failed to add duplicate collection element "DefaultDocumentModule". )
جهت حذف ماژول دستور زیر را صادر کنید:
Appcmd.exe uninstall module MODULE_NAME
نمونه:
%windir%\system32\inetsrv\appcmd.exe uninstall module DefaultDocumentModule
گرفتن کوئری یا لیستی از ماژولهای فعال برای یک اپلیکیشن یا عمومی:
Appcmd.exe list modules [/app.name:APPLICATION_NAME]
سوپپچ aap.name اختیاری است ولی اگر نام یک اپلیکیشن را به آن بدهید، فقط ماژولهایی را که روی این اپلیکیشن اجرا میشوند، لیست میکند.
نمونه:
%windir%\system32\inetsrv\appcmd.exe list modules /app.name:"Default Web Site"
کد زیر هم نمونه ای برای لیست کردن تمامی ماژولهای عمومی که بر روی تمامی اپلیکیشنها اجرا میشوند:
%windir%\system32\inetsrv\appcmd.exe list modules
خط زیر یک ماژول را برای همه اپلیکیشنها یا اپلیکیشن خاصی فعال میکند که بستگی دارد سوییچ type چگونه مقداردهی شده باشد:
Appcmd.exe add module /name:MODULE_NAME /type:MGD_TYPE
برای مثال خط زیر باعث میشود ماژول Forms Authentication فقط برای وب اپلیکیشن default web site فعال شود:
%windir%\system32\inetsrv\appcmd.exe add module /name:FormsAuthentication /type:System.Web.Security.FormsAuthenticationModule /app.name:"Default Web Site"
یا در پایین آن را به صورت عمومی یا global فعال میکند:
%windir%\system32\inetsrv\appcmd.exe add module /name:FormsAuthentication /type:System.Web.Security.FormsAuthenticationModule
برای غیرفعال کردن یک ماژول از دستور زیر استفاده میشود:
Appcmd.exe delete module MODULE_NAME [/app.name:APPLICATION_NAME]
اگر غیر فعال کردن یک ماژول در یک اپلیکیشن خاص مدنظر شما باشد دستور زیر نمونه آن است:
%windir%\system32\inetsrv\appcmd.exe delete module FormsAuthentication /app.name:"Default Web Site"
اگر قصد دارید آنرا بر روی تمامی اپلیکیشنها غیرفعال کنید، دستور زیر نمونه آن است:
%windir%\system32\inetsrv\appcmd.exe delete module FormsAuthentication
حفظ کردن یا به خاطر سپردن دستورات بالا ممکن است کار سخت و دشواری باشد، به همین جهت از help کمک بگیرید:
Appcmd.exe module /?
یا به شکل اختصاصیتر برای یک دستور
Appcmd.exe install module /?Appcmd add module /?
<div ng-show="has"> <div ng-repeat="item in items"> <span>{{item.title}}</span> </div> </div>
<div ng-if="has"> <div ng-repeat="item in items"> <span>{{item.title}}</span> </div> </div>
سوال سوم، پس اگر عملکرد یکسانی دارند، تفاوت آنها در چیست؟