- ادیتور اون خیلی مناسب کاربر معمولی نیست
- در خیلی از موارد چپ چین راست چین کردن متن با مشکل مواجه میشه
- دکمههای میان بر برای خیلی از عملیات رو نداره
- موقع تایپ مطلب قابلیت WYSIWYG وجود نداره باید به preview رفت یا مطلب رو ذخیره کرد و سپس نتیجه اونو دید
Blogger auto poster
2- برنامه بصورت خودکار همیشه تمام لینکهای شر شده در یک روز را منتشر میکند و یا یک تعداد مشخصی را ؟ ( اگر مورد اول درست هست بهتر است که مورد دوم را در نسخه جدید برنامه به آن اضافه کنید )
3- چرا بعد از انجام تنظیمات برنامه با توجه به حساب کاربری خودم و اتصال موفق ، بعد از زدن دکمه Download News در میان لیست لینکهای شر شده من ، لیست لینکها منتشر شده و منتخب شما مشاهده میگردد ؟ . آیا آدرس فید شما بصورت پیش فرض در برنامه گنجانده شده است ؟: ببینید :
http://upload20.ir/upload/13207696341013548167.jpg
راه حل توصیه شده جهت برخورد با این نوع مسایل استفاده از full text search است. نگارش کامل SQL Server حاوی یک موتور FTS توکار هست . اگر از بانک اطلاعاتی خاصی استفاده میکنید که دارای موتور FTS نیست یا ... FTS مخصوص SQL Server به درد کار شما نمیخورد یا نیاز به سفارشی سازی دارد (مثلا امکان تعریف stop words فارسی (کلماتی مانند به، از، تا و امثال آن))، از موتور FTS جانبی دیگری به نام لوسین نیز میتوان استفاده کرد.
در کنار اینها ابزاری برای آنالیز و کوئری گرفتن از فایلهای ایندکس تهیه شده توسط لوسین نیز وجود دارد به نام Luke. برای نمونه اگر بانک اطلاعاتی سایت جاری را با لوسین به نحو متداولی ایندکس کنیم، در صفحه اول این برنامه، top ranking terms آن به شکل زیر ظاهر میشود:
در اینجا چون متون تهیه شده از نوع HTML هستند، تگ br در آنها زیاد است و یا یک سری حروف و کلمات فارسی هم در صدر قرار دارند که بهتر است از لیست ایندکس حذف شوند. برای اینکار تنها کافی است یک hash table را به نحو زیر تعریف و به StandardAnalyzer لوسین ارسال کنیم:
var stopWords = new Hashtable(); stopWords.Add("br","br"); // ... var analyzer = new StandardAnalyzer(Version.LUCENE_29, stopWords);
یا آقای عرب عامری برای حروف و کلمات فارسی که نباید ایندکس شوند، یک لیست نسبتا جامع را در اینجا تهیه کردهاند.
اینبار اگر stop words یاد شده را اعمال و مجددا ایندکسها را تهیه کنیم به خروجی بهتری خواهیم رسید.
در کل حداقل از این لحاظ، لوسین نسبت به FTS توکار SQL Server مناسبتر به نظر میرسد.
به OpenAPI Specification عبارت Swagger Specification نیز گفته میشود؛ اما OpenAPI عبارتی است که باید ترجیح داده شود.
OpenAPI و Swagger
تا اینجا دریافتیم که استاندارد OpenAPI و یا Swagger، صرفا دو واژه برای انجام کاری مشابه هستند. اما در عمل Swagger تشکیل شدهاست از تعدادی ابزار سورس باز که برفراز استاندارد OpenAPI کار کرده و قابلیتهایی را ارائه میدهند؛ مانند Swagger Editor (برای تولید استاندارد)، Swagger UI (برای تولید UI مستندات)، Swagger CodeGen (برای تولید کدهای خودکار) و غیره. برای نمونه swagger-ui را میتوانید در مخزن کد GitHub آن ملاحظه کنید.
البته این ابزارها به صورت عمومی تهیه شدهاند. به همین جهت محصور کنندههایی نیز برای آنها جهت یکپارچگی با ASP.NET Core، طراحی شدهاند؛ مانند میانافزار Swashbuckle.AspNetCore. کار آن تولید OpenAPI Specification بر اساس ASP.NET Core 2x API شما میباشد که جزئیات انجام اینکار را به مرور بررسی خواهیم کرد. این کامپوننت به همراه یک swagger-ui جایگذاری شده (embedded) نیز میباشد که کار تهیهی یک UI خودکار را بر اساس این استاندارد میسر میکند.
البته محصورکنندههای متعددی برای ابزارهای Swagger، برای پروژههای ASP.NET Core وجود دارند که یکی دیگر از آنها NSwag است. هرچند Swashbuckle.AspNetCore پرکاربردترین مورد تا به امروز بودهاست.
ساختار نمونه برنامهای که در این سری تکمیل خواهد شد
در اینجا ساختار برنامهی ASP.NET Core 2.2x نمونهی این سری را ملاحظه میکنید که هدف اصلی آن، ارائهی دو کنترلر Web API برای کتابها و نویسندههای آنها میباشد:
برای نمونه اگر برنامه را اجرا کنید، در مسیر https://localhost:5001/api/authors، لیست تمام نویسندگانی که به صورت اطلاعات آغازین برنامه، توسط OpenAPISwaggerDoc.DataLayer ثبت شدهاند، قابل مشاهدهاست:
و یا کتابهای نویسندهای خاص را در آدرسی مانند https://localhost:5001/api/authors/2902b665-1190-4c70-9915-b9c2d7680450/books میتوان مشاهده کرد:
کدهای کامل آغازین این نمونه برنامه را از اینجا میتوانید دریافت کنید: OpenAPISwaggerDoc-01.zip و شامل این اجزا است:
- OpenAPISwaggerDoc.Entities: به همراه موجودیتهای نویسنده و کتاب است.
- OpenAPISwaggerDoc.DataLayer: شامل DbContext برنامه است؛ به همراه تعدادی رکورد پیشفرض جهت آغاز بانک اطلاعاتی و چون DbContext را در یک پروژهی مجزا قرار دادهایم، نیاز به IDesignTimeDbContextFactory نیز دارد که این مورد هم در این پروژه لحاظ شدهاست.
- OpenAPISwaggerDoc.Models: شامل DTOهای برنامه است. برای نگاشت این DTOها به موجودیتها و برعکس، از AutoMapper استفاده شدهاست که کار این نگاشتها و تعریف پروفایل متناظر با آنها، در پروژهی OpenAPISwaggerDoc.Profiles صورت میگیرد.
- OpenAPISwaggerDoc.Services: کار استفادهی از لایهی OpenAPISwaggerDoc.DataLayer را جهت دسترسی به بانک اطلاعاتی و کار با موجودیتهای کتابها و نویسندگان، انجام میدهد. از این سرویسها در دو کنترلر Web API برنامه، برای دریافت اطلاعات نویسندگان و کتابهای آنها از بانک اطلاعاتی، استفاده میشود.
- OpenAPISwaggerDoc.Web: پروژهی اصلی است که دو کنترلر Web API را هاست میکند و تنظیمات اولیهی این سرویسها را در کلاس Startup انجام داده و همچنین کار اعمال خودکار Migrations را نیز در کلاس Program (بالاترین سطح برنامه) تکمیل میکند. رشتهی اتصالی این برنامه، در فایل appsettings.json تعریف شدهاست و به یک بانک اطلاعاتی LocalDB اشاره میکند که پس از اجرای برنامه به صورت خودکار ساخته شده و مقدار دهی میشود.
در قسمت بعد، کار مستند سازی این API را شروع میکنیم.
UPDATE tbl_Changeset SET CreationDate = CreationDate - number of days set ahead WHERE CreationDate >= time when the clock got set ahead
در این مقاله با ادیتور VS Code کار میکنیم. بعد از نصب آن، از منوی Terminal، گزینهی New Terminal را کلیک کنید تا پنجرهی PowerShell نمایش داده شود؛ برای سرعت و دقت بیشتر در برنامههای vue.js ای. با دستور زیر vue cli را نصب میکنیم (فقط یک مرتبه و برای برنامههای بعدی vue.jsای، نیازی به اجرای این دستور نداریم):
npm install -g @vue/cli
جهت راه اندازی یک برنامهی پیش فرض Vue.js ای، کافیست دستور زیر را اجرا نماییم تا پکیجهای مورد نیاز، به همراه کانفیگ اولیه (Zero config) برای ما ایجاد شوند:
vue create movie-app
بعد از ایجاد برنامه در vs code، از طریق منوی File، گزینه Open Folder را کلیک کرده و پوشه برنامهای را که ایجاد کردیم، Select Folder میکنیم. ساختار اولیهی برنامهی ایجاد شده، به شکل زیر میباشد:
نیازمندیهای مثال جاری
A) برای گرفتن اطلاعات مورد نمایش در مثال جاری، از سایت omdbapi.com استفاده میکنیم که با دریافت یک api key آن بصورت رایگان، میتوانیم web serviceهای آن را Call نماییم.
B) از vuetify برای ui استفاده میکنیم که بصورت Material Design و دارای کامپوننتهای غنی میباشد؛ ضمن اینکه RTL را هم پشتیبانی میکند.
برای نصب آن در Terminal دستور زیر را اجرا میکنیم:
vue add vuetify
سپس جهت تست و صحت افزوده شدن و کانفیگ درست، با دستور زیر برنامه را اجرا میکنیم:
npm run serve
بعد از اجرای دستور فوق، روی گزینه زیر ctrl+click میکنیم تا نتیجه کار در مرورگر قابل رویت باشد:
نمایش صفحه زیر نشان دهندهی درستی انجام کار تا اینجا است:
نکته: جهت استفاده از امکان RTL کافیست در فایل vuetify.js واقع در پوشهی plugins، تغییرات زیر را انجام دهیم. در مثال جاری بدلیل اینکه اطلاعات انگلیسی میباشند، از نسخه LTR آن استفاده میکنیم؛ هر چند یکسری api فارسی نیز موجود میباشد که میتوان از آنها استفاده نمود.
import Vue from 'vue' import Vuetify from 'vuetify/lib' import 'vuetify/src/stylus/app.styl' Vue.use(Vuetify, { iconfont: 'md', rtl: true })
C) نصب vue-router : جهت انجام routeهای تودرتو ، مپ کردن کامپوننت ها با آدرسی مشخص، کار با پارامتر و HTML5 History API مورد استفاده قرار میگیرد. برای نصب آن، دستور زیر را اجرا میکنیم:
npm install vue-router
برای نوشتن routeهای مورد نیاز، یک فولدر را با نام router، در پوشه src برنامه ایجاد میکنیم و یک فایل جاوا اسکریپتی را در آن با نام index.js، میسازیم (این ساختار برای مدیریت بهتر پروژه میباشد):
درون فایل index.js، محتویات زیر را طبق مستندات آن قرار میدهیم:
import Vue from 'vue' import VueRouter from 'vue-router' Vue.use(VueRouter)
جهت استفاده از این router، نیاز است تا در نمونهی وهله سازی شدهی vue برنامه بکار گرفته شود. فایل main.js را باز کنید و خط زیر را در قسمت بالای برنامه وارد کنید:
import router from './router'
اکنون محتویات فایل main.js بشکل زیر میباشد:
import Vue from 'vue' import './plugins/vuetify' import App from './App.vue' import router from './router' Vue.config.productionTip = false new Vue({ render: h => h(App), router }).$mount('#app')
D) نصب axios : برای انجام درخواستهای HTTP و عملیات ایجکس در vue.js ترجیحا بهتر است از axios که یک کتابخانهی محبوب میباشد و کار با آن ساده است، استفاده شود. برای نصب آن، دستور زیر را اجرا میکنیم:
npm install axios
E) نصب vuex : کتابخانهای جهت مدیریت حالت (state management) برای vue.js میباشد و مشابه آن Flux و Redux برای React میباشند. برای نصب، دستور زیر را اجرا میکنیم:
npm install vuex
برای بکارگیری آن یک فولدر را با نام store در پوشهی src برنامه ایجاد میکنیم و یک فایل جاوا اسکریپتی را در آن با نام index.js میسازیم (این ساختار برای مدیریت بهتر پروژه میباشد). درون فایل index.js، محتویات زیر را طبق مستندات آن و ^ قرار میدهیم.
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export const store = new Vuex.Store()
برای استفاده و کانفیگ آن، محتویات فایل main.js را بشکل زیر تغییر دهید:
import Vue from 'vue' import './plugins/vuetify' import App from './App.vue' import router from './router' import {store} from './store' Vue.config.productionTip = false new Vue({ render: h => h(App), store, router }).$mount('#app')
نکته: برای اجرای برنامه و دریافت پکیجهای مورد استفاده در مثال جاری، نیاز است دستور زیر را اجرا کنید:
npm install
var client = new SoapDisposableEmailAddressDetectorClient(); var context = new soapContext { //todo: get your API key here: http://www.nameapi.org/en/register/ apiKey = "test" }; var result = client.isDisposable(context, "DaDiDoo@mailinator.com"); if (result.disposable.ToString() == "YES") { Console.WriteLine("YES! It's Disposable!"); }
Additional information: The remote server returned an unexpected response: (400) Bad Request.
<html><head><title>Bad Request</title></head><body><h1>Bad Request</h1><p>No api-key provided!</p></body></html>
اگر همین وب سرویس را توسط امکانات سایت http://wsdlbrowser.com بررسی کنید، بدون مشکل کار میکند. اما تفاوت در کجاست؟
خروجی ارسالی به سرور، توسط سایت http://wsdlbrowser.com به این شکل است:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://disposableemailaddressdetector.email.services.v4_0.soap.server.nameapi.org/"> <SOAP-ENV:Body> <ns1:isDisposable> <context> <apiKey>test</apiKey> </context> <emailAddress>sdsdg@site.com</emailAddress> </ns1:isDisposable> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <isDisposable xmlns="http://disposableemailaddressdetector.email.services.v4_0.soap.server.nameapi.org/"> <context xmlns=""><apiKey>test</apiKey></context> <emailAddress xmlns="">DaDiDoo@mailinator.com</emailAddress> </isDisposable> </s:Body> </s:Envelope>
برای این منظور به سه کلاس ذیل خواهیم رسید:
public class EndpointBehavior : IEndpointBehavior { public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { } public void Validate(ServiceEndpoint endpoint) { } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { clientRuntime.MessageInspectors.Add(new ClientMessageInspector()); } } public class ClientMessageInspector : IClientMessageInspector { public void AfterReceiveReply(ref Message reply, object correlationState) { } public object BeforeSendRequest(ref Message request, System.ServiceModel.IClientChannel channel) { request = new MyCustomMessage(request); return request; } } /// <summary> /// To customize WCF envelope and namespace prefix /// </summary> public class MyCustomMessage : Message { private readonly Message _message; public MyCustomMessage(Message message) { _message = message; } public override MessageHeaders Headers { get { return _message.Headers; } } public override MessageProperties Properties { get { return _message.Properties; } } public override MessageVersion Version { get { return _message.Version; } } protected override void OnWriteStartBody(XmlDictionaryWriter writer) { writer.WriteStartElement("Body", "http://schemas.xmlsoap.org/soap/envelope/"); } protected override void OnWriteBodyContents(XmlDictionaryWriter writer) { _message.WriteBodyContents(writer); } protected override void OnWriteStartEnvelope(XmlDictionaryWriter writer) { writer.WriteStartElement("SOAP-ENV", "Envelope", "http://schemas.xmlsoap.org/soap/envelope/"); writer.WriteAttributeString("xmlns", "ns1", null, value: "http://disposableemailaddressdetector.email.services.v4_0.soap.server.nameapi.org/"); } }
var client = new SoapDisposableEmailAddressDetectorClient(); client.Endpoint.Behaviors.Add(new EndpointBehavior());
کدهای کامل این مثال را از اینجا میتوانید دریافت کنید.
چند نکته تکمیلی برای امنیت بیشتر
1- بهتر است که فایل روی دیتابیس ذخیره شود، در غیر اینصورت نام فایل و پسوند توسط سیستم تعیین شود.
2- نام و پسوند ارسالی در نظر گرفته نشود.
3- با اندازه گیری سایز فایل GIF نمیتوان به معتبر بودن آن اطمینان داشت.
http://www.pyxsoft.com/en/hacking-hackers.html
http://www.exploit-db.com/exploits/16181/
روش متداول کار با کتابخانهی iTextSharp ، ایجاد شیء Document ، سپس ایجاد PdfWriter برای نوشتن در آن، گشودن سند و ... افزودن اشیایی مانند Paragraph ، PdfPTable ، PdfPCell و غیره به آن است و در نهایت بستن سند. راه میانبری هم برای کار با این کتابخانه وجود دارد و آن هم استفاده از امکانات فضای نام iTextSharp.text.html.simpleparser آن میباشد. به این ترتیب میتوان به صورت خودکار، یک محتوای HTML را تبدیل به فایل PDF کرد.
مثال : نمایش یک متن HTML ساده انگلیسی
using System.Diagnostics;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.html.simpleparser;
using iTextSharp.text.pdf;
namespace HeadersAndFooters
{
class Program
{
static void Main(string[] args)
{
using (var pdfDoc = new Document(PageSize.A4))
{
PdfWriter.GetInstance(pdfDoc, new FileStream("Test.pdf", FileMode.Create));
pdfDoc.Open();
var html = @"<span style='color:blue'><b>Testing</b></span>
<i>iTextSharp's</i> <u>HTML to PDF capabilities</u>";
var parsedHtmlElements = HTMLWorker.ParseToList(new StringReader(html), null);
foreach (var htmlElement in parsedHtmlElements)
{
pdfDoc.Add(htmlElement);
}
}
//open the final file with adobe reader for instance.
Process.Start("Test.pdf");
}
}
}
نکتهی جدید کد فوق، استفاده از متد HTMLWorker.ParseToList است. به این ترتیب parser کتابخانهی iTextSharp وارد عمل شده و html تعریف شده را به معادل المانهای بومی خودش تبدیل میکند؛ مثلا تبدیل به chunk یا pdfptable و امثال آن. در نهایت در طی یک حلقه، این عناصر به صفحه اضافه میشوند.
البته باید دقت داشت که HTMLWorker امکان تبدیل عناصر پیچیده، تودرتو و چندلایه HTML را ندارد؛ اما بهتر از هیچی است!
همهی اینها خوب! اما به درد ما فارسی زبانها نمیخورد. همین متغیر html فوق را با یک متن فارسی جایگزین کنید، چیزی نمایش داده نخواهد شد. البته این هم نکته دارد که در ادامه ذکر خواهد شد.
جهت نمایش متون فارسی نیاز است تا نکات ذکر شده در مطلب «فارسی نویسی و iTextSharp» رعایت شوند که شامل:
- تعیین صریح قلم
- تعیین encoding
- استفاده از عناصر دربرگیرندهای است که خاصیت RunDirection را پشتیبانی میکنند؛ مانند PdfPCell و غیره
به این ترتیب خواهیم داشت:
using System.Diagnostics;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.html.simpleparser;
using iTextSharp.text.pdf;
using iTextSharp.text.html;
namespace HeadersAndFooters
{
class Program
{
static void Main(string[] args)
{
using (var pdfDoc = new Document(PageSize.A4))
{
PdfWriter.GetInstance(pdfDoc, new FileStream("Test.pdf", FileMode.Create));
pdfDoc.Open();
//روش صحیح تعریف فونت
FontFactory.Register("c:\\windows\\fonts\\tahoma.ttf");
StyleSheet styles = new StyleSheet();
styles.LoadTagStyle(HtmlTags.BODY, HtmlTags.FONTFAMILY, "tahoma");
styles.LoadTagStyle(HtmlTags.BODY, HtmlTags.ENCODING, "Identity-H");
var html = @"<span style='color:blue'><b>آزمایش</b></span>
کتابخانه <i>iTextSharp</i> <u>جهت بررسی فارسی نویسی</u>";
var parsedHtmlElements = HTMLWorker.ParseToList(new StringReader(html), styles);
PdfPCell pdfCell = new PdfPCell { Border = 0 };
pdfCell.RunDirection = PdfWriter.RUN_DIRECTION_RTL;
foreach (var htmlElement in parsedHtmlElements)
{
pdfCell.AddElement(htmlElement);
}
var table1 = new PdfPTable(1);
table1.AddCell(pdfCell);
pdfDoc.Add(table1);
}
//open the final file with adobe reader for instance.
Process.Start("Test.pdf");
}
}
}
همانطور که ملاحظه میکنید ابتدا قلمی در cache قلمهای این کتابخانه ثبت میشود (FontFactory.Register). سپس نوع قلم و encoding آن توسط یک StyleSheet تعریف شده و به HTMLWorker.ParseToList ارسال میگردد و در نهایت به کمک یک المان دارای RunDirection، در صفحه نمایش داده میشود.
نکته:
ممکن است که به متغیر html ، یک table ساده html را نسبت دهید. در این حالت پس از تنظیم style یاد شده، در هر سلول این html table ، متون فارسی به صورت معکوس نمایش داده خواهند شد که این هم یک نکتهی کوچک دیگر دارد:
foreach (var htmlElement in parsedHtmlElements)
{
if (htmlElement is PdfPTable)
{
var table = (PdfPTable)htmlElement;
table.RunDirection = PdfWriter.RUN_DIRECTION_RTL;
foreach (var row in table.Rows)
{
foreach (var cell in row.GetCells())
{
cell.RunDirection = PdfWriter.RUN_DIRECTION_RTL;
}
}
}
pdfCell.AddElement(htmlElement);
}
در قسمتی که قرار است المانهای معادل به pdfCell اضافه شوند، آنها را بررسی کرده و RunDirection آنها را RTL خواهیم کرد.
کاربردها:
بدیهی است این حالت برای تهیه گزارشات پیشرفتهتر برای مثال تهیه قالبهایی که در حین تهیه PDF ، قسمتهایی از آنها توسط برنامه نویس Replace میشوند، بسیار مناسب است.
همچنین مطلب «بارگذاری یک یوزرکنترل با استفاده از جیکوئری» و متد RenderUserControl مطرح شده در آن که در نهایت یک قطعه کد HTML را به صورت رشته به ما تحویل میدهد، میتواند جهت تهیه گزارشهای پویایی که برای مثال قسمتی از آن یک GridView بایند شده حاصل از یک یوزر کنترل است، مورد استفاده قرار گیرد.