<div condition="Model.Approved"> <p> This website has <strong surround="em">@Model.Approved</strong> been approved yet. Visit www.contoso.com for more information. </p> </div> <div condition="!User.Identity.IsAuthenticated">I'm not a valid user</div> <div condition="User.Identity.IsAuthenticated">I can use the system</div>
مستند سازی ASP.NET Core 2x API توسط OpenAPI Swagger - قسمت ششم - تکمیل مستندات محافظت از API
services.AddSwaggerGen(c => { // ... var security = new Dictionary<string, IEnumerable<string>> { {"Bearer", new string[] { }}, }; c.AddSecurityDefinition("Bearer", new ApiKeyScheme { Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", Name = "Authorization", In = "header", Type = "apiKey" }); c.AddSecurityRequirement(security); });
public class CustomContext : DbContext { public CustomContext() : base("AppConfigConnectionStringName") { } // or public class CustomContext : DbContext { public CustomContext() : base(@"Data Source=(local);Initial Catalog=MyDBName;Integrated Security=True;Pooling=False") { }
var ctx = new MyContext(); ctx.Database.Connection.ConnectionString = "...";
Database.DefaultConnectionFactory = new SqlConnectionFactory(@"Data Source=(local);Initial Catalog=MyDBName;Integrated Security=True;Pooling=False");
'System.Data.Entity.Core.EntityException'
<connectionStrings> <clear /> <add name="DefaultConnection" connectionString="Data Source=.;Initial Catalog=MVC5DB;Integrated Security = true" providerName="System.Data.SqlClient" /> </connectionStrings>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework"> <parameters> <parameter value="Data Source=.;Integrated Security=True" /> </parameters> </defaultConnectionFactory>
var infoTable = new PdfPTable(6)
{
WidthPercentage = 100,
RunDirection = PdfWriter.RUN_DIRECTION_RTL,
ExtendLastRow = false,
SpacingBefore = 15,
};
infoTable.DefaultCell.Border = 2;
infoTable.AddCell(new PdfPCell(new Phrase("اطلاعات شناسنامه ای", tfont))
{
RunDirection = PdfWriter.RUN_DIRECTION_RTL,
HorizontalAlignment = Element.ALIGN_LEFT,
Border = 2,
PaddingBottom = 15,
Colspan=2
});
infoTable.AddCell(new PdfPCell(new Phrase("اطلاعات خانوادگی", tfont))
{
RunDirection = PdfWriter.RUN_DIRECTION_RTL,
HorizontalAlignment = Element.ALIGN_LEFT,
Border = 2,
PaddingBottom = 15,
Colspan = 2
});
infoTable.AddCell(new PdfPCell(new Phrase("اطلاعات دانشگاهی", tfont))
{
RunDirection = PdfWriter.RUN_DIRECTION_RTL,
HorizontalAlignment = Element.ALIGN_LEFT,
Border = 2,
PaddingBottom = 15,
Colspan = 2
});
var universityLogoImage = Image.GetInstance(imgPath);
universityLogoImage.ScaleAbsolute(30, 30);
//این عکس رو اصلا نشون نمیده topTable.AddCell(new PdfPCell(universityLogoImage) { HorizontalAlignment = Element.ALIGN_CENTER, Border = 2, }); infoTable.AddCell(new PdfPCell(new Phrase("وضعیت تاهل:", docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 2, PaddingBottom = 10, }); infoTable.AddCell(new PdfPCell(new Phrase(dt.Rows[0][22].ToString() == "0" ? "مجرد" : "متاهل", docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 2, PaddingBottom = 10, }); infoTable.AddCell(new PdfPCell(new Phrase("کد تحصیلی:", docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 2, PaddingBottom = 10, }); infoTable.AddCell(new PdfPCell(new Phrase(dt.Rows[0][0].ToString(), docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 2, PaddingBottom = 10, }); infoTable.AddCell(new PdfPCell(new Phrase("تحصیلات همسر:", docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 2, PaddingBottom = 10, }); infoTable.AddCell(new PdfPCell(new Phrase(dt.Rows[0]["wife_edu"].ToString(), docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 2, PaddingBottom = 10, }); infoTable.AddCell(new PdfPCell(new Phrase("شماره پرونده:", docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 2, PaddingBottom = 10, }); infoTable.AddCell(new PdfPCell(new Phrase(dt.Rows[0]["t_parvande_num"].ToString(), docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 2, PaddingBottom = 10, }); infoTable.AddCell(new PdfPCell(new Phrase("تحصیلات پدر:", docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 2, PaddingBottom = 10, }); infoTable.AddCell(new PdfPCell(new Phrase(dt.Rows[0]["father_edu"].ToString(), docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 2, PaddingBottom = 10, }); infoTable.AddCell(new PdfPCell(new Phrase("کد مرکز خدمات:", docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 2, PaddingBottom = 10, }); infoTable.AddCell(new PdfPCell(new Phrase(dt.Rows[0]["bime_code"].ToString(), docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 2, PaddingBottom = 10, }); infoTable.AddCell(new PdfPCell(new Phrase("شغل پدر:", docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 2, PaddingBottom = 10, }); infoTable.AddCell(new PdfPCell(new Phrase(dt.Rows[0]["father_job"].ToString(), docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 2, PaddingBottom = 10, }); infoTable.AddCell(new PdfPCell(new Phrase("پایه قبولی:", docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 2, PaddingBottom = 10, }); infoTable.AddCell(new PdfPCell(new Phrase(dt.Rows[0]["enter_paye"].ToString(), docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 2, PaddingBottom = 10, }); infoTable.AddCell(new PdfPCell(new Phrase("", docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 0 }); infoTable.AddCell(new PdfPCell(new Phrase("", docFont)) { RunDirection = PdfWriter.RUN_DIRECTION_RTL, HorizontalAlignment = Element.ALIGN_LEFT, Border = 0 }); int[] infoTableColumnsWidth = { 20, 15, 20, 15,20,15 }; infoTable.SetWidths(infoTableColumnsWidth); doc.Add(infoTable);
مروری بر نحوهی توزیع برنامههای Blazor بر روی IIS
1- پیش از هر کاری باید مطابق نگارش ASP.NET Core در حال استفاده (که به عنوان هاست Blazor Server و یا ارائه دهندهی قسمت Web API برنامهی سمت کلاینت WASM مطرح است)، بستهی NET Core hosting bundle. را نصب کرد که عموما تحت عنوان «Hosting Bundle Installer» قابل دریافت است.
نکتهی مهم: همانند تمام نگارشهای دات نت، در اینجا نیز باید Hosting Bundle را پس از نصب IIS، بر روی سیستم نصب کرد. اگر این ترتیب تغییر کند، یکبار دیگر نصاب آنرا اجرا کرده و گزینهی ترمیم نصب را انتخاب کنید تا یکپارچگی آن با IIS صورت گیرد.
2- نیاز است برنامهی خود را اصطلاحا publish کرد تا به همراه فایلهای نهایی قابل کپی باشد که در پوشهای توسط IIS هاست خواهند شد. برای اینکار اگر از نگارش کامل ویژوال استودیو استفاده میکنید، فقط کافی است بر روی پروژهی مدنظر کلیک راست کرده و از منوی باز شده، گزینهی publish را انتخاب کنید و مراحل آنرا طی نمائید و یا این مراحل را میتوان توسط دستور خط فرمان زیر نیز خلاصه کرد که وابستگی خاصی، به IDE ویژهای ندارد و چند سکویی است:
dotnet publish -o "c:\dir1\dir2" -c Release
و یا اگر فقط دستور dotnet publish -c Release را در ریشهی پروژه اجرا کنیم، خروجی نهایی را در پوشهی bin\Release\net5.0\publish میتوان مشاهده کرد که به همراه یک web.config مخصوص برنامههای blazor هم هست و در آن mime typeهای متناظری، به همراه URL rewriting مناسب برنامههای تک صفحهای وب از پیش تنظیم شدهاست. بنابراین در اینجا نصب ماژول URL rewrite بر روی IIS نیز الزامی است.
3- در اینجا نیز همانند تنظیمات برنامههای ASP.NET Core، باید application pool منتسب به برنامه را ویرایش کرده و NET Clr Version. آنرا بر روی No Managed Code قرار داد.
روش فعالسازی توزیع مبتنی بر فشرده سازی Brotli در IIS
در حین عملیات publish استاندارد، به صورت پیشفرض از تمام فایلها، سه نسخهی اصلی، gz شده (gzip) و یا br شده (فشرده سازی Brotli که فایلهای کم حجمتری را نسبت به gz ارائه میدهد) نیز تهیه میشوند که بسته به نوع مرورگر و پشتیبانی آن از روشهای مختلف فشرده سازی، یکی از آنها در اختیار کلاینت قرار خواهد گرفت که به این صورت کاربران، تجربهی دریافت کم حجمتر و سریعتری را خواهند داشت.
باید دقت داشت Web.config ای که به همراه دستور dotnet publish ایجاد میشود، روش توزیع پیشفرض فایلهای br. تولیدی را ندارد. برای اینکار نیاز است تنظیمات این فایل web.config توصیه شدهی توسط تیم Blazor را به web.config خود اضافه کرد تا در نهایت حجم دریافتی از سرور به شدت کاهش یابد.
یک نکته: اگر میخواهید فایل web.config سفارشی خودتان را داشته باشید، نمونهای از آنرا در ریشهی پروژه قرار داده و سپس فایل csproj را به نحو زیر ویرایش کنید تا از آن در حین publish استفاده کند:
<PropertyGroup> <PublishIISAssets>true</PublishIISAssets> </PropertyGroup>
در حین publish برنامههای Blazor WASM کار IL trimming نیز انجام میشود
برای کاهش حجم نهایی برنامههای Blazor WASM، در حین publish در حالت release، کار IL Trimming نیز به صورت خودکار انجام میشود تا کدهای IL ای که در برنامه نقش نداشتهاند و مستقیما در جائی استفاده نشدهاند، به صورت خودکار حذف شوند و به این ترتیب حجم ارائهی نهایی به شدت کاهش یابد.
فقط باید دقت داشت که در این حالت اگر عملیات پویایی مانند reflection در کدهای شما صورت میگیرد، به علت نداشتن ارجاع استاتیکی به منابع مورد استفاده، در زمان اجرا با مشکل مواجه خواهد شد. اگر میخواهید اخطارهایی را در این زمینه مشاهده کنید، گزینهی زیر را به فایل csproj اضافه نمائید:
<SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings>
حذف مباحث بومی سازی در صورت عدم نیاز
اگر در برنامهی خود از مباحث time-zones استفاده نمیکنید، میتوانید با غیرفعال کردن آن در فایل csproj، حداقل 100 کیلوبایت از حجم برنامهی نهایی را کاهش دهید:
<BlazorEnableTimeZoneSupport>false</BlazorEnableTimeZoneSupport>
<InvariantGlobalization>true</InvariantGlobalization>
برای شناسایی ایرادات در کد و بهبود کیفیت کدها میتوانید از ابزارهای دستهی lint استفاده کنید که تعدادی از معروفترین این ابزارها (jslint ,cpplint ,eslint ,nodelint و ...) هستند.
برای نصب چنین ابزاری مثل lint میتوانید به شکل زیر آن را نصب کنید:
npm install -g eslint
برای اولین بار نیاز است که آماده سازی ابتدایی برای این کتابخانه صورت بگیرد که با دستور زیر قابل انجام است:
eslint --init
? How would you like to configure ESLint? Answer questions about your style ? Are you using ECMAScript 6 features? Yes ? Are you using ES6 modules? Yes ? Where will your code run? Browser, Node ? Do you use CommonJS? No ? Do you use JSX? No ? What style of indentation do you use? Spaces ? What quotes do you use for strings? Double ? What line endings do you use? Windows ? Do you require semicolons? Yes ? What format do you want your config file to be in? JSON Successfully created .eslintrc.json file in D:\ali\electron
eslint . یا eslint index.js
میتوانید این دستور را در در خصوصیت test، در بخش اسکریپت، به شکل زیر وارد کنید:
{ "name": "electron", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "start": "electron .", "test":"eslint ." }, "author": "", "license": "ISC" }
npm test
D:\ali\electron\index.js 1:26 error Strings must use doublequote quotes 16:8 error Strings must use doublequote quotes 19:3 error Expected indentation of 4 space characters but found 2 indent 22:3 error Expected indentation of 4 space characters but found 2 indent ✖ 4 problems (4 errors, 0 warnings)
برای نامگذاری فایلهای js، به جای استفاده از _ از - استفاده کنید. این قاعدهای است که گیت هاب در نامگذاری فایلهای js انجام میدهد. یعنی به جای عبارت dotnet_tips.js از عبارت dotnet-tips.js استفاده کنید. خاطرتان جمع باشد که هیچ فایل جاوااسکرپیتی رسمی در الکترون، خارج از این قاعده نامگذاری نشده است.
سعی کنید از جدیدترین قواعد موجود در ES6 استفاده کنید مانند:
let برای تعریف متغیرها
const برای تعریف ثابت ها
توابع جهتی به جای نوشتن عبارت function
استفاده از template stringها به جای چسباندن رشتهها از طریق عملگر +
برای نامگذاری متغیرها از همان قوانین تعریف شده برای node.js استفاده کنید که شامل موارد زیر است:
- موقعی که یک ماژول را به عنوان یک کلاس استفاده میکنید از متد CamelCase استفاده کنید مثل BrowserWindow
- موقعی که از یک ماژول که حاوی مجموعهای از دستورات و apiها است استفاده میکنید، از قانون mixedCase استفاده کنید مثل app یا globalShortcut
- موقعی که یک api به عنوان خصوصیت یک شیء مورد استفاده قرار میگیرد، از mixedCase استفاده کنید؛ به عنوان مثال win.webContents یا fs.readFileSync
- برای مابقی اشیا مثل دستورات process و یا تگ webview که به شکل متفاوتتری مورد استفاده قرار میگیرند، از همان عنوانهای خودشان استفاده میکنیم.
موقعی که api جدیدی را میسازید و قصد تعریف متدی را دارید بهتر است دو متد برای get و set تعریف شود، نسبت به حالتی که در کتابخانه جی کوئری مورد استفاده قرار میگیرد یعنی عبارتهای زیر
setText('test'); getText();
.text([text]);
در قسمت قبلی درباره ایجاد نمودار سازمانی تحت وب صحبت کردیم .حال اگر بخواهیم آن را با رنگهای مختلف ایجاد کنیم مانند شکل ذیل :
بدین صورت باید عمل کنیم:
نمودار در داخل canvas رسم شده است. برای اینکه پس زمینه (background) و حاشیههای آن (borders) را رنگ آمیزی کنیم، باید تابع رنگ آمیزی را قبل از تابع رسم نمودار صدا بزنیم. میتوانید از کدهای ذیل استفاده نمائید:
// ایجاد یک پس زمینه رنگی: var c = document.getElementById("c_canvas"); var cxt = c.getContext("2d"); var gradient = cxt.createLinearGradient(0, 0, 800, 320) gradient.addColorStop(0, 'Red'); gradient.addColorStop(.5, 'Yellow'); gradient.addColorStop(1, 'Green'); cxt.fillStyle = gradient; cxt.fillRect(0, 0, 800, 320); cxt.save(); // این سه خط را فعال کرده تا انتقال نمودار چارت سازمانی را مشاهده نمائید. //cxt.scale(-1.1, 1.1); //cxt.translate(-700,-50); //cxt.rotate(0.2); var o = new orgChart(); o.addNode(1, '', '', 'Root node'); o.addNode(2, 1, 'u', 'u-node 1'); o.addNode(3, 1, 'u', 'u-node 2'); o.addNode(4, 1, 'u', 'u-node 3'); o.addNode(5, 1, 'l', 'l-node 1'); o.addNode(6, 1, 'l', 'l-node 2'); o.addNode(7, 1, 'r', 'r-node 1'); o.addNode(8, 1, 'r', 'r-node 2'); o.addNode(9, 1, 'r', 'r-node 3'); o.addNode('', '', '', 'Root 2'); o.addNode('', 'Root 2', 'r', 'using'); o.addNode('', 'Root 2', 'r', 'text as id'); o.drawChart('c_canvas', 'center'); cxt.restore();
نکته : اگر بخواهید رنگ پس زمینه canvas را کامل پر کند (Fill) باید رسم نمودار را دوبار انجام دهید، در ابتدا تعریف یک canvas با امکان پرشونده در صفحه ، و بعد رسم پس زمینه و بعد رسم دوباره canvas .
رنگها
شاخهها میتوانند رنگهای متفاوتی داشته باشند. امکان تعریف رنگ شاخهها بهمراه صدا زدن تابع addNode وجود دارد. اگر رنگی تعریف نشود ، از رنگ پیشفرض استفاده خواهد شد. رنگهای کنونی را با صدا زدن تابع setColor میتوان عوض کرد و تا زمان صدا زدن تابع setColor بعدی از آنها استفاده خواهد شد. همه خطهایی که شاخهها را به هم متصل میکنند فقط یک رنگ مشابه میتوانند داشته باشند.
پارامترهای تابع setColor :
- رنگ خطوط حاشیه ( اختیاری )
- رنگ پرکننده شاخه ( اختیاری )
- رنگ نوشته / عنوان شاخه ( اختیاری )
- رنگ خطوط متصل کننده ( اختیاری ، عمومی )
یک پارامتر خالی رنگ ، تنظیمات کنونی را تغییر نخواهد داد. کد زیر را ویرایش نموده و دوباره صفحه خود را بازخوانی نمائید.
var o = new orgChart(); o.setColor('#99CC99', '#CCFFCC', '#000000', '#FF0000'); o.addNode(0, '', '', 'Root node'); o.setColor('#CCCC66', '#FFFF99'); o.addNode(11, 0, 'u', 'u-node 1'); o.setColor('#000000', '#FFFF99'); o.addNode(12, 0, 'u', 'black border'); o.addNode(13, 0, 'u', 'bold black border', 1); o.setColor('#CC4950', '#FF7C80'); o.addNode(21, 0, 'l', 'l-node 1'); o.addNode(22, 0, 'l', 'l-node 2', 0, 'BLACK', 'RED', 'BLUE'); o.addNode(23, 0, 'l', 'l-node 3'); o.setColor('#CC9966', '#FFCC99'); o.addNode(31, 0, 'r', 'r-node 1'); o.drawChart('c_colors', 'center');
در پروژه هایی به صورت Smart UI کد نویسی شده اند و یا حتی قصد انجام پروژه با تکنولوژیهای WPF یا Windows Application را دارید و نیاز دارید که فرمهای خود را به صورت generic بسازید این مقاله به شما کمک خواهد کرد.
#Windows Application
یک پروژه از نوع Windows Application ایجاد میکنیم و یک فرم به نام FrmBase در آن خواهیم داشت. یک Label در فرم قرار دهید و مقدار Text آن را فرم اصلی قرار دهید.
در فرم مربوطه، فرم را به صورت generic تعریف کنید. به صورت زیر:
public partial class FrmBase<T> : Form where T : class { public FrmBase() { InitializeComponent(); } }
بعد باید همین تغییرات را در فایل FrmBase.designer.cs هم اعمال کنیم:
partial class FrmBase<T> where T : class { /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// Clean up any resources being used. /// </summary> /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> protected override void Dispose( bool disposing ) { if ( disposing && ( components != null ) ) { components.Dispose(); } base.Dispose( disposing ); } #region Windows Form Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { this.label1 = new System.Windows.Forms.Label(); this.SuspendLayout(); // // label1 // this.label1.AutoSize = true; this.label1.Location = new System.Drawing.Point(186, 22); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(51, 13); this.label1.TabIndex = 0; this.label1.Text = "فرم اصلی"; // // FrmBase // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(445, 262); this.Controls.Add(this.label1); this.Name = "FrmBase"; this.Text = "Form1"; this.ResumeLayout(false); this.PerformLayout(); } #endregion private System.Windows.Forms.Label label1; }
public partial class FrmTest : FrmBase<String> { public FrmTest() { InitializeComponent(); } }
با این که برنامه به راحتی اجرا میشود و خروجی آن قابل مشاهده است ولی امکان نمایش فرم در حالت design وجود ندارد. متاسفانه در Windows Appها برای تعریف فرمها به صورت generic یا این مشکل روبرور هستیم. تنها راه موجود برای حل این مشکل استفاده از یک کلاس کمکی است. به صورت زیر:
public partial class FrmTest : FrmTestHelp { public FrmTest() { InitializeComponent(); } } public class FrmTestHelp : FrmBase<String> { }
#WPF
در پروژههای WPF ، راه حلی برای این مشکل در نظر گرفته شده است. در WPF، برای Window یا UserControl پایه نمیتوان Designer داشت. ابتدا باید فرم پایه را به صورت زیر ایجاد کنیم:
public class WindowBase<T> : Window where T : class { }
public partial class MainWindow: WindowBase<String> { public MainWindow() { InitializeComponent(); } }
<local:WindowBase x:Class="GenericWindows.MainWindow"
x:TypeArguments="sys:String" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:GenericWindows" xmlns:sys="clr-namespace:System;assembly=mscorlib" Title="MainWindow" Height="350" Width="525"> <Grid> </Grid> </local:WindowBase>
بالاخره گوگل کار تهیه API مخصوص ابزار Analytics خود را به پایان رساند و اکنون برنامه نویسها میتوانند همانند سایر سرویسهای گوگل از این ابزار گزارشگیری نمایند.
خلاصه کاربردی این API ، دو صفحه تعاریف پروتکل (+) و ریز مواردی (+) است که میتوان گزارشگیری نمود.
هنوز کتابخانه google-gdata جهت استفاده از این API به روز رسانی نشده است؛ بنابراین در این مقاله سعی خواهیم کرد نحوه کار با این API را از صفر بازنویسی کنیم.
مطابق صفحه تعاریف پروتکل، سه روش اعتبارسنجی جهت دریافت اطلاعات API معرفی شده است که در اینجا از روش ClientLogin که مرسومتر است استفاده خواهیم کرد.
مطابق مثالی که در آن صفحه قرار دارد، اطلاعاتی شبیه به اطلاعات زیر را باید ارسال و دریافت کنیم:
POST /accounts/ClientLogin HTTP/1.1
User-Agent: curl/7.15.1 (i486-pc-linux-gnu) libcurl/7.15.1
OpenSSL/0.9.8a zlib/1.2.3 libidn/0.5.18
Host: www.google.com
Accept: */*
Content-Length: 103
Content-Type: application/x-www-form-urlencoded
accountType=GOOGLE&Email=userName@google.com&Passwd=myPasswrd&source=curl-tester-1.0&service=analytics
HTTP/1.1 200 OK
Content-Type: text/plain
Cache-control: no-cache
Pragma: no-cache
Date: Mon, 02 Jun 2008 22:08:51 GMT
Content-Length: 497
SID=DQ...
LSID=DQAA...
Auth=DQAAAG8...
string getSecurityToken()
{
if (string.IsNullOrEmpty(Email))
throw new NullReferenceException("Email is required!");
if (string.IsNullOrEmpty(Password))
throw new NullReferenceException("Password is required!");
WebRequest request = WebRequest.Create("https://www.google.com/accounts/ClientLogin");
request.Method = "POST";
string postData = "accountType=GOOGLE&Email=" + Email + "&Passwd=" + Password + "&service=analytics&source=vahid-testapp-1.0";
byte[] byteArray = Encoding.ASCII.GetBytes(postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;
using (Stream dataSt = request.GetRequestStream())
{
dataSt.Write(byteArray, 0, byteArray.Length);
}
string auth = string.Empty;
using (WebResponse response = request.GetResponse())
{
using (Stream dataStream = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(dataStream))
{
string responseFromServer = reader.ReadToEnd().Trim();
string[] tokens = responseFromServer.Split('\n');
foreach (string token in tokens)
{
if (token.StartsWith("SID="))
continue;
if (token.StartsWith("LSID="))
continue;
if (token.StartsWith("Auth="))
{
auth = token.Substring(5);
}
else
{
throw new AuthenticationException("Error authenticating Google user " + Email);
}
}
}
}
}
return auth;
}
همانطور که ملاحظه میکنید به آدرس https://www.google.com/accounts/ClientLogin ، اطلاعات postData با متد POST ارسال شده (دقیقا مطابق توضیحات گوگل) و سپس از پاسخ دریافتی، مقدار نشانه Auth را جدا نموده و در ادامه عملیات استفاده خواهیم کرد. وجود این نشانه در پاسخ دریافتی به معنای موفقیت آمیز بودن اعتبار سنجی ما است و مقدار آن در طول کل عملیات باید نگهداری شده و مورد استفاده مجدد قرار گیرد.
سپس مطابق ادامه توضیحات API گوگل باید لیست پروفایلهایی را که ایجاد کردهایم پیدا نمائیم:
string getAvailableProfiles(string authToken)
{
return fetchPage("https://www.google.com/analytics/feeds/accounts/default", authToken);
}
متد fetchPage را از پیوست این مقاله میتوانید دریافت نمائید. خروجی یک فایل xml است که با انواع و اقسام روشهای موجود قابل آنالیز است، از کتابخانههای XML دات نت گرفته تا Linq to xml و یا روش serialization که من روش آخر را ترجیح میدهم.
مرحله بعد، ساخت URL زیر و دریافت مجدد اطلاعات مربوطه است:
string url = string.Format("https://www.google.com/analytics/feeds/data?ids={0}&metrics=ga:pageviews&start-date={1}&end-date={2}", id, from, to);
return fetchPage(url, auth);
فایلهای کلاسهای مورد استفاده را از اینجا دریافت نمائید.
مثالی در مورد نحوه استفاده از آن:
CGoogleAnalytics cga = new CGoogleAnalytics
{
Email = "username@gmail.com",
Password = "password",
From = DateTime.Now.Subtract(TimeSpan.FromDays(1)),
To = DateTime.Now.Subtract(TimeSpan.FromDays(1))
};
List<CGoogleAnalytics.SitePagePreviews> pagePreviews =
cga.GetTotalNumberOfPageViews();
foreach (var list in pagePreviews)
{
//string site = list.Site;
//int pw = list.PagePreviews;
}