Simple 3D Coverflow is a fully 3D multimedia coverflow slider plugin that allows to display multimedia content with an unique original layout from a 3D perspective. It’s perfect for any kind of presentation, for anyone that wants to deliver a great impact to thier visitors. It runs on all major browsers and mobile devices like iPhone, iPad, IOS, Android and Windows. When a thumbnail is clicked you can choose to do nothing, display multimedia content using our great revolution lightbox or to open a new webpage.
آموزش مقدماتی WebGL
WebGL is an in-browser 3D renderer based on OpenGL, which lets you display your 3D content directly into an HTML5 page. Throughout this series I will cover all the essentials you need to get started using this framework. We'll start with an introduction, then we'll be building on to the framework that we used in part one as well as adding a model importer and a custom class for 3D objects. You will also be introduced to animation and controls. Lastly, we’ll take a look at lighting and adding 2D objects to your scene.
در یک نمودار یا چارت سازمانی در حد امکان شاخهها همواره در کنار هم و جمع و جور رسم میشوند. در مثال زیر نود u-Node 1 و u-Node 3 دارای زیر شاخه نبوده ، بنابراین نیازی به فضای زیرین جهت نمایش ندارند. جهت مشاهده این فضا میتوانید خط مشخص شده در کد را فعال نمائید و تفاوت فضای مورد نیاز و ایجاد شده را ببینید.
دو درخت نمودار متفاوت در کنار هم رسم شده اند. هیچ همپوشانی بین درختان رسم شده وجود ندارد ( بنابراین نود Root 2 روی نود u-Node 3 رسم نشده است.
var o = new orgChart(); o.addNode( 0, '', '', 'Root 1'); o.addNode( 1, 0, 'u', 'u-Node 1'); o.addNode( 2, 0, 'u', 'u-Node 2'); o.addNode( 3, 0, 'u', 'u-Node 3'); o.addNode( 4, 0, 'u', 'u-Node 4');
//میتوانید خط زیر را فعال نمائید تا تفاوت فضای ایجاد شده و مورد نیاز را مشاهده نمائید.
//o.addNode( 9, 3, 'u', 'EXTRA', 0, '', '#CC0000', '#FF0000'); o.addNode(11, 2, 'l', 'l-Node'); o.addNode(12, 2, 'u', 'u-Node'); o.addNode(13, 2, 'u', 'u-Node'); o.addNode(14, 2, 'r', 'r-Node'); o.addNode(20, 4, 'l', 'l-Node'); o.addNode(21, '', '', 'Root 2'); o.drawChart('c_layout');
نمونه زیر یک مثال کامل میباشد. انواع اتصالهای تو در تو چندگانه در این نمونه استفاده شده است .
این هم کد نمونه فوق :
var o = new orgChart(); o.setFont('Arial', 18); o.addNode( 0, '', '', 'President', 1); o.setFont('Arial', 12); o.addNode('', 0, 'l', 'Control'); o.addNode('', 0, 'l', 'Secretary'); o.addNode('', 0, 'l', 'Marketing'); o.addNode('', 0, 'l', 'Human resources'); o.setColor('#99CC99', '#CCFFCC'); o.addNode(12, 0, 'r', 'Facility'); o.addNode('', 12, 'r', 'IT'); o.addNode('', 12, 'r', 'Resource planning'); o.setFont('Arial', 18); o.setColor('#CCCC66', '#FFFF99'); o.addNode(20, 0, 'u', 'Projects', 1); o.setFont('Arial', 12); o.addNode('', 20, 'r', 'Management'); o.addNode('', 20, 'r', 'Finance'); o.addNode('', 20, 'l', 'Development'); o.addNode('', 20, 'l', 'Maintenance'); o.addNode('', 20, 'l', 'Specials'); o.setColor('#CC4950', '#FF7C80'); o.setFont('Arial', 18); o.addNode(30, 0, 'u', 'Specials', 1); o.setFont('Arial', 12); o.addNode(31, 30, 'l', 'Management'); o.addNode('', 30, 'l', 'Communication'); o.addNode(33, 30, 'r', 'Development'); o.addNode(34, 33, 'r', 'Maintenance'); o.addNode('', 33, 'r', 'Special A'); o.addNode('', 33, 'r', 'Special B'); o.addNode('', 33, 'r', 'Advice'); o.addNode('', 30, 'l', 'Taskforce'); o.setColor('#CC9966', '#FFCC99'); o.setFont('Arial', 18); o.addNode(40, 0, 'u', 'Programming', 1); o.setFont('Arial', 12); o.addNode(41, 40, 'l', 'Management'); o.addNode(42, 40, 'l', 'Finance'); o.addNode('', 40, 'r', 'Assessment'); o.addNode('', 40, 'r', 'Coding team'); o.addNode('', 40, 'r', 'Quality control'); o.drawChart('c_ex1', '', true);
شما میتوانید به نودها تصویر دلخواه خود را نیز اضافه نمائید. تصاویر بصورت عمودی قرار خواهند گرفت و در صورتی که بزرگ باشند تغییر اندازه خواهند داد. ( فراخوانی تابع setSize قبل از اضافه کردن عکس در این مثال )
کدهای مثال فوق :
var o = new orgChart(); o.setSize(120, 60); o.setFont('Arial', 18); o.addNode( 1, '', '', 'Icon smiley', 0, '', '', '', '', 'pic/smiley.gif'); o.addNode( 2, '', '', 'This is a tree', 0, '', '', '', '', 'pic/tree.jpg'); o.addNode( 3, 2, 'u', 'This is a tree'); o.addNode( 4, '', '', 'Right Top smiley', 0, '', '', '', '', 'pic/smiley.gif', 'rt'); o.addNode( 5, '', '', 'Center bottom smiley', 0, '', '', '', '', 'pic/smiley.gif', 'cb'); o.drawChart('c_img');
یک مثال دیگر از استفاده تصاویر در چارت :
var o = new orgChart(); o.setSize(60, 110); o.setFont('Arial', 12); o.addNode( 1, '', '', 'Hominidae'); o.addNode( 10, 1, 'l', 'Hominidae'); o.addNode( 11, 10, 'l', 'Hominini'); o.addNode( 12, 10, 'r', 'Gorillini'); o.addNode( 20, 1, 'r', 'Ponginae'); o.addNode( '', 11, '', 'Homo Sapiens', '', '', '', '', '', 'pic/homo.jpg', 'ct'); o.addNode( '', 11, '', 'Pan', '', '', '', '', '', 'pic/pan.jpg', 'ct'); o.addNode( '', 12, '', 'Gorilla', '', '', '', '', '', 'pic/gorilla.jpg', 'ct'); o.addNode( '', 20, '', 'Pongo', '', '', '', '', '', 'pic/pongo.jpg', 'ct'); o.drawChart('c_img2', 'c');
عدم امکان استفاده از مرورگر IE تا نسخه 8 ، چرا که IE هیچ پشتیبانی از toDataURL در excanvas.js را انجام نمیدهد.
شما میتوانید از توابع استاندارد canvas در جهت تبدیل محتویات canvas به تصویر استاتیک استفاده نمائید. برای اینکه بتوانید این کار را تست نمائید باید کد ذیل را در همان صفحه ای که کد ( یک مثال کامل ) را استفاده کردید درج نمائید و در این صورت با کلیک بر روی لینک اول میتوانید یک تصویر با فرمت png در یک صفحه جدید از نمودار خود بدست بیاورید و یا با کلیک بر روی لینک دوم یک تصویر را دانلود نمائید.
<script type="text/javascript"> function openAsPng(id){ window.open(document.getElementById(id).toDataURL("image/png")); } function saveAsPng(id){ var img = document.getElementById(id).toDataURL("image/png"); document.location.href = img.replace("image/png", "image/octet-stream"); } </script> <a href = "javascript:openAsPng('c_ex1');">Click here to open the image as png in a new window</a><BR> <a href = "javascript:saveAsPng('c_ex1');">Click here to save the image as png</a><BR>
نمایش چارت فقط بصورت یک تصویر :
برای اینکه بتوانید یک چارت ایجاد شده از این روش را فقط بصورت یک تصویر نمایش دهید باید عمل تبدیل به عکس را بلافاصله پس از رسم نمودار در canvas انجام دهید بدین صورت که در کد ذیل مشاهده مینمائید:
<canvas id="c_pngchart" width="1" height="1">Your browser does not support canvas!</canvas> <img id="pngchart"> <script type="text/javascript"> var o = new orgChart(); o.addNode(0, '', '', 'Root'); o.addNode(1, 0, 'u', 'u-Node 1'); o.addNode(2, 0, 'u', 'u-Node 2'); o.drawChart('c_pngchart', '', true); var canvas = document.getElementById('c_pngchart'); document.getElementById("pngchart").src = canvas.toDataURL("image/png"); // The html keyword "hidden" doesn't work in IE, so resize the canvas to NUL canvas.height = 0; canvas.width = 0; </script>
همه لینکهایی که در نودها ایجاد شده است غیرفعال شده و از کار میافتند. بنابراین برای انجام این کار ،یک المنت تصویر در صفحه خود ایجاد ، نمودار را در canvas رسم نموده ، نمودار را به تصویر تبدیل نموده و آن را به المنت تصویر مقید میکنیم و در آخر canvas مخفی میکنیم. برای این منظور از کلید واژه hidden استفاده میکنیم که در IE این کلمه باز قابل شناسایی نبوده و باید از روش تخصیص اندازه طول و عرض صفر 0 استفاده شود یعنی width=0 , height=0
تصویر فوق ایجاد شده کد مورد نظر میباشد.
تغییر اندازه پویا :
اگر بخواهید بصورت پویا اندازه canvas را تغییر دهید ، نمودار شما ناپدید میشود و پس از تغییر اندازه ، نمودار پاک خواهد شد.
برای رسم نمودار باید دوباره از توابع drawChart() یا redrawChart() استفاده نمائید.
برای رسم نودها نیازی به تعریف دوباره آنها نمیباشد ( مخصوصا در مثالی که در این صفحه برای شما ارائه شده است )
تابع ()drowChart تمامی نودها را در زمان رسم دوباره جاگذاری میکند ، در صورتی که اگر شما میدانید چارت شما به غیر از اندازه هیچ تغییر دیگری نداشته میتوانید با فراخوانی تابع redrawChart یک کپی از همان چارت را که در حافظه canvas وجود دارد را رسم نمائید.
از تمامی دوستان خوبم تشکر میکنم که این مطلب را دنبال نمودند . ما را از نظرات خوب و سازنده خود بی نصیب نفرمائید.
درخواست همزمان گزارش
C:\Windows\System32\inetsrv\config\applicationHost.config
جدول خصوصیت ها
خصوصیت | توضیح |
customLogPluginClsid | یک پارامتر رشتهای اختیاری که در آن، آی دی کلاس یا کلاسهایی نوشته میشود که برای custom logging نوشته شدهاند و این گزینه ترتیب اجرای آنها را تعیین میکند. |
directory | اختیاری است. محل ذخیرهی لاگ فایلها را مشخص میکند و در صورتیکه ذکر نشود، همان مسیر پیش فرض است. |
enabled | اختیاری است. فعال بودن سیستم لاگ برای آن سایت را مشخص میکند. مقدار پیش فرض آن true است. |
flushByEntryCountW3CLog | این مقدار مشخص میکند چند رخداد باید اتفاق بیفتد تا عمل ذخیره سازی لاگ صورت گیرد. اگر بعد از هر رخداد عمل ثبت لاگ انجام شود، سرعت ثبت لاگها بالا میرود؛ ولی باعث استفادهی مداوم از منابع و همچنین درخواست ثبت اطلاعات را روی دیسک خواهد داد و تاوان آن با زیاد شدن عملیات روی دیسک، پرداخته خواهد شد. ولی در حالتیکه چند رخداد را نگهداری سپس دستهای ثبت کند، باعث افزایش کارآیی و راندمان سرور خواهد شد. در صورتیکه سرور به مشکلات لحظهای برخورد میکند مقدار آن را کاهش دهید. مقدار پیش فرض 0 است. یعنی اینکه ثبت، بعد از 64000 لاگ خواهد بود. |
localTimeRollover | نحوهی نامگذاری فایلهای لاگ را مشخص میکند که مقدار بولین گرفته و اختیاری است. به طور پیش فرض مقدار false دارد. |
logExtFileFlags | این گزینه در حالتی به کارتان میآید که فرمت W3C را برای ثبت لاگها انتخاب کرده باشید و در اینجا مشخص میکنید که چه فیلدهایی باید در لاگ باشند و اگر بیش از یکی بود میتوان با ، (کاما) از هم جدایشان کرد. |
logFormat | نوع فرمت ذخیره سازی لاگها |
logSiteId | اختیاری است و مقدار پیش فرض آن true است. بدین معنا که کد یا شمارهی سایت هم در لاگ خواهد بود و این در حالتی است که گزارش در سطح سرور باشد. در غیر این صورت اگر هر سایت، جداگانه لاگی برای خود داشته باشد، ذکر نمیگردد. |
logTargetW3C | اختیاری است و و مقدار file و *ETW را میگیرد که به طور پیش فرض روی File تنظیم است. در این حالت فایل لاگها در یک فایل متنی توسط http.sys ذخیره میشود. ولی موقعیکه از ETW استفاده میشود، http.sys با استفاده از iislogprovider دادهها را به سمت ETW ارسال میکند که منجر به اجرای سرویس Logsvc شده که از دادهها کوئری گرفته و آنها را مستقیما از پروسههای کارگر جمع آوری و به سمت فایل لاگ ارسال میکند. همچنین انتخاب این دو گزینه نیز ممکن است. |
maxLogLineLength | حداکثر تعداد خطی که یک لاگ میتواند داشته باشد تا اینکه بتوانید در مصرف دیسک سخت صرفه جویی کنید و بیشتر کاربرد آن برای لاگهای کاستوم است. این عدد باید از نوع Uint باشد و اختیاری است و از 2 تا 65536 مقدار میپذیرد که مقدار پیش فرض آن 65536 میباشد. |
period | همان مبحث زمان بندی در مورد ایجاد فایلهای لاگ است که در مقالهی پیشین برسی کردیم و مقادیر Dialy,Hourly,monthlyو weekly را میپذیرد. همچنین maxsize هم هست؛ موقعی که لاگ به نهایت حجمی که برای آن تعیین کردیم میرسد. |
truncateSize | اختیاری است و مقدار آن از نوع int64 است. حداکثر حجم یک فایل لاگ را مشخص میکند تا اگر period روی maxsize تنظیم شده بود، حداکثر حجم را میتوان از اینجا تعیین نمود. در مقاله پیشین در این باره صحبت کردیم؛ حداقل عدد برای آن 1,048,576 است و اگر کمتر از آن بنویسید، سیستم همین عدد 1,048,576 را در نظر خواهد گرفت. مقدار پیش فرض آن 20971520 می باشد. |
<system.applicationHost> <sites> <siteDefaults> <logFile logFormat="W3C" directory="%SystemDrive%\inetpub\logs\LogFiles" enabled="true"> <customFields> <clear/> <add logFieldName="ContosoField" sourceName="ContosoSource" sourceType="ServerVariable" /> </customFields> </logFile> </siteDefaults> </sites> </system.applicationHost>
تغییر تنظمیات لاگ با Appcmd
appcmd.exe set config -section:system.applicationHost/sites /siteDefaults.logFile.enabled:"True" /commit:apphost appcmd.exe set config -section:system.applicationHost/sites /siteDefaults.logFile.logFormat:"W3C" /commit:apphost appcmd.exe set config -section:system.applicationHost/sites /siteDefaults.logFile.directory:"%SystemDrive%\inetpub\logs\LogFiles" /commit:apphost
تنظمیات تگ لاگ با برنامه نویسی و اسکریپت نویسی
using System; using System.Text; using Microsoft.Web.Administration; internal static class Sample { private static void Main() { using (ServerManager serverManager = new ServerManager()) { Configuration config = serverManager.GetApplicationHostConfiguration(); ConfigurationSection sitesSection = config.GetSection("system.applicationHost/sites"); ConfigurationElement siteDefaultsElement = sitesSection.GetChildElement("siteDefaults"); ConfigurationElement logFileElement = siteDefaultsElement.GetChildElement("logFile"); logFileElement["logFormat"] = @"W3C"; logFileElement["directory"] = @"%SystemDrive%\inetpub\logs\LogFiles"; logFileElement["enabled"] = true; serverManager.CommitChanges(); } } }
با استفاده از اسکریپت نویسی توسط جاوااسکریپت و وی بی اسکریپت هم نیز این امکان مهیاست:
var adminManager = new ActiveXObject('Microsoft.ApplicationHost.WritableAdminManager'); adminManager.CommitPath = "MACHINE/WEBROOT/APPHOST"; var sitesSection = adminManager.GetAdminSection("system.applicationHost/sites", "MACHINE/WEBROOT/APPHOST"); var siteDefaultsElement = sitesSection.ChildElements.Item("siteDefaults"); var logFileElement = siteDefaultsElement.ChildElements.Item("logFile"); logFileElement.Properties.Item("logFormat").Value = "W3C"; logFileElement.Properties.Item("directory").Value = "%SystemDrive%\\inetpub\\logs\\LogFiles"; logFileElement.Properties.Item("enabled").Value = true; adminManager.CommitChanges();
FTP Logging
IIS را باز کنید و در لیست درختی، سرور را انتخاب کنید. در قسمت FTP میتوانید گزینهی Ftp logging را ببینید. تنظیمات این قسمت هم دقیقا همانند قسمت logging میباشد و همان موارد برای آن هم صدق میکند.
بررسی تگ آن در applicationhost
تگ این نوع لاگ در فایل applicationhost در زیر مجموعهی تگ <site> به شکل زیر نوشته میشود:
<system.ftpServer> <log centralLogFileMode="Central"> <centralLogFile enabled="true" /> </log> </system.ftpServer>
گزینه centralLogFileMode دو مقدار central و site را میپذیرد. اگر گزینهی central انتخاب شود، یعنی همهی لاگها را داخل یک فایل در سطح سرور ثبت کن ولی اگر گزینهی site انتخاب شده باشد، لاگ هر سایت در یک فایل ثبت خواهد شد.
گزینهی logInUTF8 یک خصوصیت اختیاری است که مقدار پیش فرض آن true میباشد. در این حالت باید تمامی رشتهها به انکدینگ UTF-8 تبدیل شوند.
همانطور که میبینید تگ log در بالا یک تگ فرزند هم به اسم centralLogFile دارد که همان خصوصیات جدول بالا در آن مهیاست.
دسترسی به تنظیمات این قسمت توسط دستور Appcmd:
appcmd.exe set config -section:system.ftpServer/log /centralLogFileMode:"Central" /commit:apphost appcmd.exe set config -section:system.ftpServer/log /centralLogFile.enabled:"True" /commit:apphost
دسترسی به تنظیمات این قسمت توسط دات نت:
using System; using System.Text; using Microsoft.Web.Administration; internal static class Sample { private static void Main() { using (ServerManager serverManager = new ServerManager()) { Configuration config = serverManager.GetApplicationHostConfiguration(); ConfigurationSection logSection = config.GetSection("system.ftpServer/log"); logSection["centralLogFileMode"] = @"Central"; ConfigurationElement centralLogFileElement = logSection.GetChildElement("centralLogFile"); centralLogFileElement["enabled"] = true; serverManager.CommitChanges(); } } }
دسترسی به تنظیمات این قسمت توسط Javascript:
var adminManager = new ActiveXObject('Microsoft.ApplicationHost.WritableAdminManager'); adminManager.CommitPath = "MACHINE/WEBROOT/APPHOST"; var logSection = adminManager.GetAdminSection("system.ftpServer/log", "MACHINE/WEBROOT/APPHOST"); logSection.Properties.Item("centralLogFileMode").Value = "Central"; var centralLogFileElement = logSection.ChildElements.Item("centralLogFile"); centralLogFileElement.Properties.Item("enabled").Value = true; adminManager.CommitChanges();
بحثی در مورد تغییرات اخیر سایت Medium
javascript:location.href='https://webcache.googleusercontent.com/search?q=cache:'+encodeURIComponent(location.href)
یک مشکلی هم که خیلی ها بعد از ایجاد تغییرات جدید به گودر می گیرند اینه که اگر بخوای مطلبی رو نشر بدی حتما باید اونرو +1 کنی و بعد نشر بدی درصورتی که شاید اون مطلب رو دوست نداشته باشی ،
ولی اینکار لازم نیست ، اگر در گودر در حال مطالعه مطلبی هستید وقتی در نوار سیاه رنگ بالا روی دکمه [Share...] کلیک کنید ، خودش لینک مطلبی رو که در حال مطالعه اش هستید تشخیص میده و به متن شما وصله می کنه ، برای بعضی ها کلا شاید این شیوه نشر دادن مطالب راحت تر باشه .
امن سازی برنامههای ASP.NET Core توسط IdentityServer 4x - قسمت چهاردهم- آماده شدن برای انتشار برنامه
public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); IdentityModelEventSource.ShowPII = true; services.AddAuthentication(options => { options.DefaultScheme = "Cookies"; options.DefaultChallengeScheme = "oidc"; options.DefaultSignOutScheme = "oidc"; }) .AddCookie("Cookies", options => { options.AccessDeniedPath = "/Authorization/AccessDenied"; // set session lifetime options.ExpireTimeSpan = TimeSpan.FromHours(8); // sliding or absolute options.SlidingExpiration = false; // host prefixed cookie name options.Cookie.Name = "MVC"; // strict SameSite handling options.Cookie.SameSite = SameSiteMode.Strict; }) .AddOpenIdConnect("oidc", options => { options.SignInScheme = "Cookies"; options.Authority = Configuration["IDPBaseAddress"]; options.ClientId = Configuration["ClientId"]; options.ClientSecret = Configuration["ClientSecret"]; options.ResponseType = "code id_token"; options.ResponseMode = "query"; options.RequireHttpsMetadata = false; options.CallbackPath = new PathString("/Home/"); options.SignedOutCallbackPath = new PathString("/Home/"); options.MapInboundClaims = true; options.Scope.Clear(); options.Scope.Add("openid"); options.Scope.Add("profile"); options.Scope.Add("roles"); options.Scope.Add("PS.WebApi.Read"); options.Scope.Add("offline_access"); options.SaveTokens = true; options.GetClaimsFromUserInfoEndpoint = true; //options.UsePkce = true; //options.ClaimActions.MapJsonKey(claimType: "role", jsonKey: "role"); // for having 2 or more roles options.TokenValidationParameters = new TokenValidationParameters { NameClaimType = JwtClaimTypes.GivenName, RoleClaimType = JwtClaimTypes.Role }; }); //ServicePointManager.Expect100Continue = true; //ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls // | SecurityProtocolType.Tls11 // | SecurityProtocolType.Tls12 // | SecurityProtocolType.Ssl3; } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "areas", pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}" ); //.RequireAuthorization(); endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}" ); //.RequireAuthorization(); }); //[HttpPost] //public IActionResult Logout() //{ // return SignOut("Cookies", "oidc"); //} }
پروژههای بنده به ترتیب Endpoint هاشون اینگونه هست:
"IDPBaseAddress": "https://localhost:44310",
"ClientId": "Mvc_ClientId",
"ClientSecret": "WebMvc"
{ "IdentityServerData": { "IdentityResources": [ { "Name": "roles", "Enabled": true, "DisplayName": "Roles", "UserClaims": [ "role" ] }, { "Name": "openid", "Enabled": true, "Required": true, "DisplayName": "Your user identifier", "UserClaims": [ "sub" ] }, { "Name": "profile", "Enabled": true, "DisplayName": "User profile", "Description": "Your user profile information (first name, last name, etc.)", "Emphasize": true, "UserClaims": [ "name", "family_name", "given_name", "middle_name", "nickname", "preferred_username", "profile", "picture", "website", "gender", "birthdate", "zoneinfo", "locale", "updated_at" ] }, { "Name": "email", "Enabled": true, "DisplayName": "Your email address", "Emphasize": true, "UserClaims": [ "email", "email_verified" ] }, { "Name": "address", "Enabled": true, "DisplayName": "Your address", "Emphasize": true, "UserClaims": [ "address" ] } ], "ApiScopes": [ { "Name": "Idp_Admin_ClientId_api", "DisplayName": "Idp_Admin_ClientId_api", "Required": true, "UserClaims": [ "role", "name" ] }, { "Name": "WebApi.Read", "DisplayName": "WebApi Read", "Required": true, "UserClaims": [ "role", "WebApi.Read" ] }, { "Name": "WebApi.Write", "DisplayName": "WebApi Write", "Required": true, "UserClaims": [ "role", "WebApi.Write" ] } ], "ApiResources": [ { "Name": "Idp_Admin_ClientId_api", "Scopes": [ "Idp_Admin_ClientId_api" ] }, { "Name": "WebApi", "Scopes": [ "WebApi.Read", "WebApi.Write" ] } ], "Clients": [ { "ClientId": "Idp_Admin_ClientId", "ClientName": "Idp_Admin_ClientId", "ClientUri": "https://localhost:44303", "AllowedGrantTypes": [ "authorization_code" ], "RequirePkce": true, "ClientSecrets": [ { "Value": "Idp_Admin_ClientSecret" } ], "RedirectUris": [ "https://localhost:44303/signin-oidc" ], "FrontChannelLogoutUri": "https://localhost:44303/signout-oidc", "PostLogoutRedirectUris": [ "https://localhost:44303/signout-callback-oidc" ], "AllowedCorsOrigins": [ "https://localhost:44303" ], "AllowedScopes": [ "openid", "email", "profile", "roles" ] }, { "ClientId": "Idp_Admin_ClientId_api_swaggerui", "ClientName": "Idp_Admin_ClientId_api_swaggerui", "AllowedGrantTypes": [ "authorization_code" ], "RequireClientSecret": false, "RequirePkce": true, "RedirectUris": [ "https://localhost:44302/swagger/oauth2-redirect.html" ], "AllowedScopes": [ "Idp_Admin_ClientId_api" ], "AllowedCorsOrigins": [ "https://localhost:44302" ] }, //WebApi { "ClientId": "WebApi_ClientId", "ClientName": "WebApi_ClientId", "ClientUri": "https://localhost:44365", "AllowedGrantTypes": [ "authorization_code" ], "RequirePkce": true, "ClientSecrets": [ { "Value": "WebApi" } ], "RedirectUris": [ "https://localhost:44303/signin-oidc" ], "FrontChannelLogoutUri": "https://localhost:44303/signout-oidc", "PostLogoutRedirectUris": [ "https://localhost:44303/signout-callback-oidc" ], "AllowedCorsOrigins": [ "https://localhost:44303", "https://localhost:44310" ], "AllowedScopes": [ "openid", "email", "profile", "roles" ] }, //Mvc { "ClientId": "Mvc_ClientId", "ClientName": "Mvc_ClientId", "ClientUri": "https://localhost:44332", "AllowedGrantTypes": [ "hybrid" ], //"RequirePkce": true, "AllowPlainTextPkce": false, "ClientSecrets": [ { "Value": "WebMvc" } ], "RedirectUris": [ "https://localhost:44332/signin-oidc" ], "FrontChannelLogoutUri": "https://localhost:44332/signout-oidc", "PostLogoutRedirectUris": [ "https://localhost:44332/signout-callback-oidc" ], "AllowedCorsOrigins": [ "https://localhost:44332", "https://localhost:44310" ], "AllowedScopes": [ "openid", "email", "profile", "roles", "address", "PS.webApi" ], "AllowAccessTokensViaBrowser": true, "RequireConsent": false, "AllowOfflineAccess": true //"UpdateAccessTokenClaimsOnRefresh": true } ] } }
public class HomeController : Controller { private readonly ILogger<HomeController> _logger; public HomeController(ILogger<HomeController> logger) { _logger = logger; } public IActionResult Default() { return View(); } public IActionResult Index() { return View(); } [Authorize] public IActionResult Privacy() { return View(); } [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] public IActionResult Error() { return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); } }
اما در نهایت بعد از اجرا و مراجعه به آدرس https://localhost:44332/home/privacy که مزین به اتریبیوت
[Authorize]میباشد با خطای زیر مواجه میشوم:
لازم به توضیح هست که پروپرتی RequireHttpsMetadata = false میباشد.
تنظیمات ابتدایی Kendo UI Editor
در ذیل کدهای سمت کاربر فعال سازی مقدماتی Kendo UI را مشاهده میکنید. در قسمت tools آن، لیست امکانات و نوار ابزار مهیای آن درج شدهاند.
دو مورد insertImage و insertFile آن نیاز به تنظیمات سمت کاربر و سرور بیشتری دارند.
<!--نحوهی راست به چپ سازی --> <div class="k-rtl"> <textarea id="editor" rows="10" cols="30" style="height: 440px"></textarea> </div> @section JavaScript { <script type="text/javascript"> $(function () { $("#editor").kendoEditor({ tools: [ "bold", "italic", "underline", "strikethrough", "justifyLeft", "justifyCenter", "justifyRight", "justifyFull", "insertUnorderedList", "insertOrderedList", "indent", "outdent", "createLink", "unlink", "insertImage", "insertFile", "subscript", "superscript", "createTable", "addRowAbove", "addRowBelow", "addColumnLeft", "addColumnRight", "deleteRow", "deleteColumn", "viewHtml", "formatting", "cleanFormatting", "fontName", "fontSize", "foreColor", "backColor", "print" ], imageBrowser: { messages: { dropFilesHere: "فایلهای خود را به اینجا کشیده و رها کنید" }, transport: { read: { url: "@Url.Action("GetFilesList", "KendoEditorImages")", dataType: "json", contentType: 'application/json; charset=utf-8', type: 'GET', cache: false }, destroy: { url: "@Url.Action("DestroyFile", "KendoEditorImages")", type: "POST" }, create: { url: "@Url.Action("CreateFolder", "KendoEditorImages")", type: "POST" }, thumbnailUrl: "@Url.Action("GetThumbnail", "KendoEditorImages")", uploadUrl: "@Url.Action("UploadFile", "KendoEditorImages")", imageUrl: "@Url.Action("GetFile", "KendoEditorImages")?path={0}" } }, fileBrowser: { messages: { dropFilesHere: "فایلهای خود را به اینجا کشیده و رها کنید" }, transport: { read: { url: "@Url.Action("GetFilesList", "KendoEditorFiles")", dataType: "json", contentType: 'application/json; charset=utf-8', type: 'GET', cache: false }, destroy: { url: "@Url.Action("DestroyFile", "KendoEditorFiles")", type: "POST" }, create: { url: "@Url.Action("CreateFolder", "KendoEditorFiles")", type: "POST" }, uploadUrl: "@Url.Action("UploadFile", "KendoEditorFiles")", fileUrl: "@Url.Action("GetFile", "KendoEditorFiles")?path={0}" } } }); }); </script> }
منهای قسمت thumbnailUrl، عملکرد قسمتهای مختلف افزودن فایل و تصویر این ادیتور یکسان هستند. به همین جهت میتوان برای مثال کنترلی مانند KendoEditorFilesController را ایجاد و سپس در کنترلر KendoEditorImagesController از آن ارث بری کرد و متد دریافت و نمایش بند انگشتی تصاویر را افزود. به این ترتیب دیگر نیازی به تکرار کدهای مشترک بین این دو قسمت نخواهد بود.
نمایش لیست پوشهها و تصویر در ابتدای باز شدن صفحهی درج تصویر
با کلیک بر روی دکمهی نمایش لیست تصاویر، صفحه دیالوگی مانند شکل زیر ظاهر خواهد شد:
تنظیمات خواندن این فایلها، از قسمت read مربوط به imageBrowser دریافت میشود که cache آن نیز به false تنظیم شدهاست تا در این بین مرورگر اطلاعات را کش نکند. این مورد در حین حذف فایلها و پوشهها مهم است. زیرا اگر cache:false تنظیم نشده باشد، حذف یک فایل یا پوشه در سمت کاربر تاثیری نخواهد داشت.
imageBrowser: { transport: { read: { url: "@Url.Action("GetFilesList", "KendoEditorImages")", dataType: "json", contentType: 'application/json; charset=utf-8', type: 'GET', cache: false } } },
namespace KendoUI13.Controllers { public class KendoEditorFilesController : Controller { //مسیر پوشه فایلها protected string FilesFolder = "~/files"; protected string KendoFileType = "f"; protected string KendoDirType = "d"; [HttpGet] public ActionResult GetFilesList(string path) { path = GetSafeDirPath(path); var imagesList = new DirectoryInfo(path) .GetFiles() .Select(fileInfo => new KendoFile { Name = fileInfo.Name, Size = fileInfo.Length, Type = KendoFileType }).ToList(); var foldersList = new DirectoryInfo(path) .GetDirectories() .Select(directoryInfo => new KendoFile { Name = directoryInfo.Name, Type = KendoDirType }).ToList(); return new ContentResult { Content = JsonConvert.SerializeObject(imagesList.Union(foldersList), new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }), ContentType = "application/json", ContentEncoding = Encoding.UTF8 }; } protected string GetSafeDirPath(string path) { // path = مسیر زیر پوشهی وارد شده if (string.IsNullOrWhiteSpace(path)) { return Server.MapPath(FilesFolder); } //تمیز سازی امنیتی path = Path.GetDirectoryName(path); path = Path.Combine(Server.MapPath(FilesFolder), path); return path; } } }
namespace KendoUI13.Models { public class KendoFile { public string Name { set; get; } public string Type { set; get; } public long Size { set; get; } } }
- علت استفاده از CamelCasePropertyNamesContractResolver در حین بازگشت JSON نهایی، تبدیل خواص دات نتی، به نامهای سازگار با JavaScript است. برای مثال به صورت خودکار Name را تبدیل به name میکند.
- پارامتر path در ابتدای کار خالی است. اما کاربر میتواند در بین پوشههای باز شدهی توسط مرورگر تصاویر Kendo UI حرکت کند. به همین جهت مقدار آن باید هربار بررسی شده و بر این اساس لیست فایلها و پوشههای جاری بازگشت داده شوند.
مدیریت حذف تصاویر و پوشهها
همانطور که در شکل فوق نیز مشخص است، با انتخاب یک پوشه یا فایل، دکمهای با آیکن ضربدر جهت فراهم آوردن امکان حذف، ظاهر میشود. این دکمه متصل است به قسمت destroy تنظیمات ادیتور:
imageBrowser: { transport: { destroy: { url: "@Url.Action("DestroyFile", "KendoEditorImages")", type: "POST" } } },
namespace KendoUI13.Controllers { public class KendoEditorFilesController : Controller { //مسیر پوشه فایلها protected string FilesFolder = "~/files"; protected string KendoFileType = "f"; protected string KendoDirType = "d"; [HttpPost] public ActionResult DestroyFile(string name, string path) { //تمیز سازی امنیتی name = Path.GetFileName(name); path = GetSafeDirPath(path); var pathToDelete = Path.Combine(path, name); var attr = System.IO.File.GetAttributes(pathToDelete); if ((attr & FileAttributes.Directory) == FileAttributes.Directory) { Directory.Delete(pathToDelete, recursive: true); } else { System.IO.File.Delete(pathToDelete); } return Json(new object[0]); } } }
- پارامتر name دریافتی مساوی است با نام فایل انتخاب شده و path مشخص میکند که در کدام پوشه قرار داریم.
- چون در اینجا امکان حذف یک پوشه یا فایل وجود دارد، حتما نیاز است بررسی کنیم، مسیر دریافتی پوشهاست یا فایل و سپس بر این اساس جهت حذف آنها اقدام صورت گیرد.
مدیریت ایجاد یک پوشهی جدید
تنظیمات قسمت create مرورگر تصاویر، مرتبط است به زمانیکه کاربر با کلیک بر روی دکمهی +، درخواست ایجاد یک پوشهی جدید را کردهاست:
imageBrowser: { transport: { create: { url: "@Url.Action("CreateFolder", "KendoEditorImages")", type: "POST" } } },
namespace KendoUI13.Controllers { public class KendoEditorFilesController : Controller { //مسیر پوشه فایلها protected string FilesFolder = "~/files"; protected string KendoFileType = "f"; protected string KendoDirType = "d"; [HttpPost] public ActionResult CreateFolder(string name, string path) { //تمیز سازی امنیتی name = Path.GetFileName(name); path = GetSafeDirPath(path); var dirToCreate = Path.Combine(path, name); Directory.CreateDirectory(dirToCreate); return KendoFile(new KendoFile { Name = name, Type = KendoDirType }); } protected ActionResult KendoFile(KendoFile file) { return new ContentResult { Content = JsonConvert.SerializeObject(file, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }), ContentType = "application/json", ContentEncoding = Encoding.UTF8 }; } } }
- پس از ایجاد پوشه، باید نام آنرا با فرمت KendoFile به صورت JSON بازگشت داد. همچنین در اینجا Type را نیز باید به d (پوشه) تنظیم کرد.
مدیریت قسمت ارسال فایل و تصویر
زمانیکه کاربر بر روی دکمهی upload file یا بارگذاری تصاویر در اینجا کلیک میکند، اطلاعات فایل آپلودی به مسیر uploadUrl ارسال میگردد.
imageBrowser: { transport: { thumbnailUrl: "@Url.Action("GetThumbnail", "KendoEditorImages")", uploadUrl: "@Url.Action("UploadFile", "KendoEditorImages")", imageUrl: "@Url.Action("GetFile", "KendoEditorImages")?path={0}" } },
در ادامه کدهای مدیریت سمت سرور قسمت آپلود این ادیتور را مشاهده میکنید:
namespace KendoUI13.Controllers { public class KendoEditorFilesController : Controller { //مسیر پوشه فایلها protected string FilesFolder = "~/files"; protected string KendoFileType = "f"; protected string KendoDirType = "d"; [HttpPost] public ActionResult UploadFile(HttpPostedFileBase file, string path) { //تمیز سازی امنیتی var name = Path.GetFileName(file.FileName); path = GetSafeDirPath(path); var pathToSave = Path.Combine(path, name); file.SaveAs(pathToSave); return KendoFile(new KendoFile { Name = name, Size = file.ContentLength, Type = KendoFileType }); } } }
- پس از ذخیره سازی اطلاعات فایل، نیاز است اطلاعات فایل نهایی را با فرمت KendoFile به صورت JSON بازگشت دهیم.
ارث بری از KendoEditorFilesController جهت تکمیل قسمت مدیریت تصاویر
تا اینجا کدهایی را که ملاحظه کردید، برای هر دو قسمت ارسال تصویر و فایل کاربرد دارند. قسمت ارسال تصاویر برای تکمیل نیاز به متد دریافت تصاویر به صورت بند انگشتی نیز دارد که به صورت ذیل قابل تعریف است و چون از کلاس پایه KendoEditorFilesController ارث بری کردهاست، این کنترلر به صورت خودکار حاوی اکشن متدهای کلاس پایه نیز خواهد بود.
using System.Web.Mvc; namespace KendoUI13.Controllers { public class KendoEditorImagesController : KendoEditorFilesController { public KendoEditorImagesController() { // بازنویسی مسیر پوشهی فایلها FilesFolder = "~/images"; } [HttpGet] [OutputCache(Duration = 3600, VaryByParam = "path")] public ActionResult GetThumbnail(string path) { //todo: create thumb/ resize image path = GetSafeFileAndDirPath(path); return File(path, "image/png"); } } }
کدهای کامل این مطلب را از اینجا میتوانید دریافت کنید.
امکان فوق از Sql Server 2005 به بعد گذاشته شده است.
منبع:
http://blog.sqlauthority.com