<?xml version="1.0"?> <Configuration xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <AllowAnonymousPush>false</AllowAnonymousPush> <Repositories>D:\GitRepo</Repositories> <AllowUserRepositoryCreation>true</AllowUserRepositoryCreation> <AllowAnonymousRegistration>false</AllowAnonymousRegistration> <DefaultLanguage>en-US</DefaultLanguage> <IsCommitAuthorAvatarVisible>true</IsCommitAuthorAvatarVisible> </Configuration>
قابلیت جالبی که در اینجا به نظر من خیلی مهم بود، استخراج تاریخچهی کامل ساب ورژن توسط گیت و انتقال همه آنها به مخزن گیت است که تنها با یک خط فرمان انجام پذیر است. برای اینکار مخرنی را در گیت ساخته و آدرس .git آن را برای اجرای فرمان نگه میداریم:
البته نصب گیت برای ویندوز برای صدور فرمان انتقال به گیت الزامی است که میتوانید از این آدرس آنرا دانلود و نصب کنید.
پس از آن در 2 مرحله مخرن ساب ورژن را به گیت انتقال میدهیم:
1- استخراج آن در یک مخزن لوکال
2- افزودن به سرور گیت (که راه اندازی شده)
برای استخراج مخزنی از ساب ورژن به یک مخزن لوکال گیت، یک فولدر خالی را ایجاد میکنیم. سپس با خط فرمان به آن وارد میشویم و بعد فرمان زیر را اجرا میکنیم:
در ادامه نام کاربری و کلمهی عبور را وارد میکنیم. البته به صورت پیش فرض، نام کاربری جاری ویندوز را در نظر میگیرد و بعد نام کاربری و کلمهی عبور سرویس ساب ورژن را میپرسد و حالا گیت کارش را شروع میکند:
پس از اتمام کار با توجه به مقالهی «مراحل ارسال یک پروژهی Visual Studio به GitHub» برای کار با گیت در ویژوال استودیو، میتوان به کار با گیت بصورت ریموت ادامه دهید.
و اما نکتهی آخر: من برای استفاده از این سرور مجبور بودم که نام localhost را با نام mehdi-pc جابجا کنم تا بتوانم از طریق یک کامپیوتر دیگر با سورس کنترل کار کنم و طی جستجوهایی که در اینترنت کردم، این کار بصورت کامند و فرمانهای شبه لینوکسی انجام پذیر بود. ولی راهی را همچون این مقاله «مشکل در جابجایی پروژههای svn» پیدا کردم که بنظرم آنرا مرتبط با موضوع میدانم و گفتن آن را خالی از لطف نمیبینم.
فایل config در واقع فایل کانفیگ داخل مخزن لوکال است؛ یعنی داخل فولدر .git و بصورت متنی ذخیره شده است:
طبق انتظار قسمتی از فایل که در زیر آمده، مربوط به مشخصات اتصال به سرور ریموت میباشد:
[remote "origin"] url = http://mehdi-pc:8551/NewsService.git fetch = +refs/heads/*:refs/remotes/origin/*
البته باید بسیار با دقت این تغییر را ایجاد کنید و مطمئن باشید که آدرس را بطور صحیح و به یک مخزن درست گیت تغییر میدهید.
در طی آزمایش اولیه این سرویس، به مشکل عجیب timeout پس از باز کردن برای مثال سومین یا چهارمین thread همزمان برای دانلود کردن اطلاعات بر خوردم. همه چیز درست بود، از کلاسها، دریافت اطلاعات از وب و غیره، اما برنامه کار نمیکرد. این مشکل فقط هم با feedburner.com رخ میداد (همانطور که مطلع هستید feedburner.com سرویسی را جهت پیگیری آمار مشترکین فیدهای شما ارائه میدهد که بسیار جالب است. برای مثال چند نفر مشترک دارید، یا یک سری نمودار و غیره. به همین جهت رسم شده است که اکثر سایتها فیدهای خودشان را در این سایت نیز ثبت میکنند).
پس از مدتی جستجو به نکته جالب زیر برخوردم که شاید برای شما هم در آینده مفید باشد:
مطابق RFC2068 - Hypertext Transfer Protocol -- HTTP/1.1 ، شما تنها مجازید 2 کانکشن فعال به یک سایت باز کنید. این علت تایم آوت در سومین thread ایجاد شده بود. برای مثال IE این مورد را محترم میشمارد. در دات نت نیز به صورت پیش فرض این محدودیت قرار داده شده است که بهسادگی میتوان آنرا تغییر داد. برای این منظور باید یک فایل app.config به پروژه اضافه کرد و سپس خطوط زیر را به آن افزود:
<configuration>
<system.net>
<connectionManagement>
<add address="*" maxconnection="100" />
</connectionManagement>
</system.net>
</configuration>
بعد از این تغییر مشکل timeout برنامه حل شد.
برای مدیریت چندین ترد همزمان دانلود کننده و در صف قرار دادن آنها در این پروژه، از کتابخانه سورس باز زیر استفاده کردم:
http://www.codeplex.com/smartthreadpool
مآخذ:
http://msdn.microsoft.com/en-us/library/fb6y0fyc.aspx
http://www.faqs.org/rfcs/rfc2068.html
http://vahidnasiri.blogspot.com
http://odetocode.com/Blogs/scott/archive/2004/06/08/272.aspx
پ.ن.
برای اینکه در بلاگر بتوانید متون حاوی xml را ارسال کنید باید از سرویس زیر استفاده کنید
http://www.elliotswan.com/postable/
در این آموزش هدف ما ایجاد برنامهای بر اساس TodoMVC است که میتواند خودش را با یک دیتابیس آنلاین همگام سازی کند.
مطمئن باشید بیشتر از 10 دقیقه وقت شمارا نخواهد گرفت !
نصب PouchDB
فایل index.html را باز کنید و فایلهای PouchDB را به آن اضافه کنید :
<script src="//cdn.jsdelivr.net/pouchdb/2.2.0/pouchdb.min.js"></script> <script src="js/base.js"></script> <script src="js/app.js"></script>
حالا PouchDB نصب شده و آماده به کار است . ( در نسخه نهایی بهتر است از فایلهای local استفاده کنید )
ایجاد بانک اطلاعاتی
بقیه کارها باید در فایل app.js انجام شود . برای شروع باید بانک اطلاعاتی جدیدی را برای درج اطلاعات خودمان ایجاد کنیم . برای ایجاد بانک اطلاعاتی خیلی ساده یک instance جدید از آبجکت PouchDB میسازیم .
var db = new PouchDB('todos'); var remoteCouch = false;
نیازی نیست که برای بانک خود، نما (Schema) ایجاد کنید! بعد از اینکه اسم را مشخص کنید، بانک آماده به کار است.
ثبت اطلاعات در بانک اطلاعاتی
اولین کاری که باید انجام دهیم این است که یک متد را ایجاد کنیم و توسط آن اطلاعات خودمان را در بانک اطلاعاتی ذخیره کنیم. نام متد را addTodo انتخاب میکنیم و کارش این است که وقتی کاربر کلید Enter را فشار داد، اطلاعات را داخل بانک اطلاعاتی ذخیره کند. متد مورد نظر به این صورت هست:
function addTodo(text) { var todo = { _id: new Date().toISOString(), title: text, completed: false }; db.put(todo, function callback(err, result) { if (!err) { console.log('Successfully posted a todo!'); } }); }
در PouchDB هر پرونده نیاز دارد تا یک فیلد unique با نام _id داشته باشد. اگر دادهای بخواهد در بانک اطلاعاتی ثبت شود و دارای _id مشابه باشد، با آن به صورت یک update رفتار خواهد شد. در اینجا ما از تاریخ با عنوان id استفاده کردیم که در این مورد خاص میباشد. شما میتواند از db.post() نیز استفاده کنید؛ اگر یک id را به صورت random میخواهید. تنها چیزی که اجباری است در هنگام ساختن یک پرونده، همین _id است و بقیه موارد کاملا اختیاری هستند.
نمایش اطلاعات
در اینجا ما از یک function کمکی به نام redrawTodosUI استفاده خواهیم کرد که وظیفهاش این است تا یک array را دریافت کرده و آن را هر طور که مشخص کردید نمایش دهد. البته آن را به سلیقه خودتان میتوانید آماده کنید.
تنها کاری که باید انجام دهیم این است که اطلاعات را از بانک اطلاعاتی استخراج کرده و به function مورد نظر پاس دهیم.
در اینجا میتوانیم به سادگی از db.allDocs برای خواندن اطلاعات از بانک اطلاعاتی استفاده کنیم.
خاصیت include_docs به PouchDB این دستور را میدهد که ما درخواست دریافت همه اطلاعات داخل پروندهها را داریم و descending هم نحوه مرتب سازی را که بر اساس _id هست، مشخص میکند تا بتوانیم جدیدترین اطلاعات را اول دریافت کنیم .
function showTodos() { db.allDocs({include_docs: true, descending: true}, function(err, doc) { redrawTodosUI(doc.rows); }); }
به روزرسانی خودکار
هر بار که ما اطلاعات جدیدی را در بانک اطلاعاتی وارد میکنیم، نیازمند این هستیم تا اطلاعات جدید را به صورت خودکار دریافت و نمایش دهیم. برای این منظور میتوانیم به روش زیر عمل کنیم :
var remoteCouch = false; db.info(function(err, info) { db.changes({ since: info.update_seq, live: true }).on('change', showTodos); });
حالا هر بار که اطلاعات جدیدی در بانک اطلاعات ثبت شود، به صورت خودکار نمایش داده خواهد شد. خاصیت live مشخص میکند که این کار میتواند بی نهایت بار انجام شود.
ویرایش اطلاعات
وقتی که کاربر یک آیتم Todo را کامل میکند، یک چک باکس را علامت میزند و اعلام میکند که این کار انجام شده است.
function checkboxChanged(todo, event) { todo.completed = event.target.checked; db.put(todo); }
این بخش شبیه به قسمت ثبت اطلاعات است، با این تفاوت که باید شامل یک فیلد _rev ( اضافه بر _id ) نیز باشد. در غیر اینصورت تغییرات ثبت نخواهد شد. این کار برای این است که اشتباهی، اطلاعاتی در بانک ثبت نشود.
حذف اطلاعات
برای حذف اطلاعات باید از متد db.remove به همراه آبجکت مورد نظر استفاده کنید .
function deleteButtonPressed(todo) { db.remove(todo); }
مانند بخش ویرایش نیز باید در اینجا هم _id و هم _rev مشخص شود.
باید توجه داشته باشید در اینجا همان آبجکتی را که از بانک فراخوانی کردهایم، به این متد پاس میدهیم.
البته شما میتونید آبجکت خودتان را نیز ایجاد کنید {_id: todo._id, _rev: todo._rev} اما خوب همان روش قبلی عاقلانهتر است و احتمال خطای کمتری دارد .
نصب CouchDB
حالا میخواهیم همگام سازی را اجرا کنیم و برای این کار نیاز هست یا CouchDB را به صورت Local نصب کنیم یا از سرویسهای آنلاین مثل IrisCouch استفاده کنید .
فعال سازی CORS
برای اینکه به صورت مستقیم با CouchDB در ارتباط باشید باید مطمئن شوید که CORS فعال هست.
در اینجا فقط نام کاربری و رمز ورود را مشخص کنید. به صورت پیش فرض CouchDB به صورت Admin Party نصب میشود و نیازی به User و password ندارد. مگر اینکه برایش مشخص کنید.
همچنین شما باید myname.iriscouch.com را با سرور خودتان جایگزین کنید که اگر به صورت local کار میکنید 127.0.0.1:5984 است.
$ export HOST=http://username:password@myname.iriscouch.com $ curl -X PUT $HOST/_config/httpd/enable_cors -d '"true"' $ curl -X PUT $HOST/_config/cors/origins -d '"*"' $ curl -X PUT $HOST/_config/cors/credentials -d '"true"' $ curl -X PUT $HOST/_config/cors/methods -d '"GET, PUT, POST, HEAD, DELETE"' $ curl -X PUT $HOST/_config/cors/headers -d \ '"accept, authorization, content-type, origin"'
راه اندازی ارتباط ساده دو طرفه
به فایل app.js برگردید . در اینجا باید آدرس بانک اطلاعاتی آنلاین را مشخص کنیم.
var db = new PouchDB('todos'); var remoteCouch = 'http://user:pass@mname.iriscouch.com/todos';
فراموش نکنید که نام کاربری و رمز ورود را بسته به نیاز خود تغییر دهید.
حالا میتونیم function که وظیفه همگام سازی اطلاعات را به عهده دارد بنویسیم :
function sync() { syncDom.setAttribute('data-sync-state', 'syncing'); var opts = {live: true}; db.replicate.to(remoteCouch, opts, syncError); db.replicate.from(remoteCouch, opts, syncError); }
db.replicate() به PouchDB میگوید که که همه اطلاعات را "به" یا "از" remoteCouch انتقال دهد.
ما دوبار این درخواست را دادیم. در بار اول اطلاعات به داخل سرور ریموت منتقل میشود و در بار دوم اطلاعات local جایگزین میشوند.
یک callback هم وقتی که این کار به پایان برسد اجرا خواهد شد .
میتوانید برنامه خود را در دو مرورگر مختلف اجرا کنید تا نتیجه کار را ببینید.
تبریک میگوییم !
شما توانستید اولین برنامه خود را توسط PouchDB ایجاد کنید. البته این یک برنامه ساده بود و در دنیای واقعی نیاز هست تا خیلی کارهای بیشتری را انجام دهید. اما باز هم اصول اولیه کار را یاد گرفتید و ادامه راه را میتوانید تنهایی ادامه دهید .
EF Code First #2
اگر تنها در محیط توسعه خودتان دارید با SQL Server لوکال سیستم کار میکنید، این خطا به معنای باز بودن یک کانکشن از management studio به SQL Server است که با بستن management studio مشکل حل میشود.
اگر دیتابیس کاری است یا دیتابیس راه دور است، باید بانک اطلاعاتی را به حالت single user دربیارید و بعد میتونید اون رو دراپ کنید.
var blogs = from blog in Blogs where blog.Name.Contains("Development") select blog;
اما اکنون چطور؟
var blogs = from blog in Blogs where blog.Name.ComputeHash() == 0 select blog;
یک مثال: بررسی تاثیر ارزیابیهای سمت کلاینت در EF Core
فرض کنید ساختار جدول بلاگها به صورت زیر است:
public class Blog { public int BlogId { get; set; } public string Url { get; set; } }
public static class StringExtensions { public static int ComputeHash(this string str) { var hash = 0; foreach (var ch in str) { hash += (int)ch; } return hash; } }
using (var context = new BloggingContext()) { var blogs = context.Blogs .Where(blog => blog.Url.ComputeHash() >= 10) .ToList(); Console.WriteLine(blogs.First().Url); }
SELECT [blog].[BlogId], [blog].[Url] FROM [Blogs] AS [blog]
الف) مفسر LINQ در EF Core، شروع به ارزیابی کوئری نوشته شده میکند و هرجائیکه متدی را یافت و از درک آن عاجز بود (معادل SQL ایی را برای آن نیافت)، آنرا از کوئری حذف میکند.
ب) کوئری SQL نهایی بدون متد ComputeHash بر روی بانک اطلاعاتی اجرا شده و نتیجه به سمت کلاینت بازگشت داده میشود. به همین جهت است که در خروجی SQL فوق خبری از متد ComputeHash نیست.
ج) اکنون که EF Core اطلاعات لازم را از سمت سرور دریافت کردهاست، متد ComputeHash را در سمت کلاینت بر روی این نتیجهی دریافتی اعمال میکند. یعنی مرحلهی آخر همان LINQ to Objects متداول خواهد بود.
به این ترتیب است که EF Core قابلیت اجرای هر نوع متدی را که معادل SQL ایی برای آن وجود ندارد، خواهد یافت.
چگونه متوجه شویم که ارزیابی سمت کلاینت رخ دادهاست؟
EF Core این قابلیت را دارد تا گزارش کاملی را از ارزیابیهای سمت کلاینت صورت گرفته ارائه دهد. هرچند در مثال فوق متد الحاقی ComputeHash بسیار واضح است، اما برای نمونه متد string.Join نیز معادل SQL ایی ندارد:
var idUrls = context.Blogs .Select(b => new { IdUrlString = string.Join(", ", b.BlogId, b.Url), }).ToList();
public class BloggingContext : DbContext { public BloggingContext() { } public BloggingContext(DbContextOptions options) : base(options) { } public DbSet<Blog> Blogs { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { if (!optionsBuilder.IsConfigured) { optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=Demo.ClientSideEvaluation;Trusted_Connection=True;"); optionsBuilder.ConfigureWarnings(warnings => { warnings.Log(CoreEventId.IncludeIgnoredWarning); warnings.Log(RelationalEventId.QueryClientEvaluationWarning); }); } } }
warn: Microsoft.EntityFrameworkCore.Query[200500] The LINQ expression 'where ([blog].Url.ComputeHash() >= 10)' could not be translated and will be evaluated locally.
اگر میخواهید ارزیابی سمت کلاینت را ممنوع کنید، در تنظیمات فوق warnings.Log را به warnings.Throw تغییر دهید. این مورد سبب خواهد شد تا اگر برنامه به این نوع ارزیابیها رسید، با یک استثناء متوقف شود (شبیه به حالت EF 6.x).
تاثیر ارزیابیهای سمت کلاینت بر روی کارآیی برنامه
هرچند قابلیت ارزیابیهای سمت کلاینت بسیار مفید است اما باید دقت داشت:
الف) در این حالت چون ابتدا متدهایی که قابلیت ارزیابی در سمت سرور را دارا نیستند، حذف خواهند شد، ممکن است تمام رکوردها به سمت کلاینت بازگشت داده شده و سپس فیلترینگ نهایی در سمت کلاینت صورت گیرد. مانند مثال محاسبهی hash که در SQL تولیدی آن، خبری از قسمت where نیست و این شرط در انتهای کار، در سمت کلاینت و به صورت LINQ to Objects اعمال میشود.
ب) این قابلیت ممکن است برنامه نویسها را از تفکر در مورد یافتن روشهای محاسباتی سمت سرور دور کند. برای مثال هر چند مثال string.Join نوشته شده در سمت کلاینت محاسبه خواهد شد و این کوئری بدون مشکل اجرا میشود، اما اگر آنرا به صورت ذیل جایگزین کنیم:
var idUrls2 = context.Blogs .Select(b => new { IdUrlString = b.BlogId + "," + b.Url }).ToList();
SELECT (CAST([b].[BlogId] AS nvarchar(max)) + N',') + [b].[Url] AS [IdUrlString] FROM [Blogs] AS [b]
کدهای کامل این مثال را از اینجا میتوانید دریافت کنید: ClientSideEvaluation.zip
- تولید درخواست به یک سایت کار سختی نیست. از این سرویسهایی که مدام سایت رو ping میکنند زیاد هست. مثل سرویسهای فید خوان. مثل سایتهایی که بررسی میکنند سایت شما آپ است یا داون.
- نه الزاما. سرویس task scheduler ویندوز همیشه در حال اجرا است؛ دقیق و منظم. این سرویس میتونه خیلی راحت یک فایل exe معمولی یا حتی یک فایل bat رو در زمانهای مشخصی اجرا کنه. برای کارهای مدیریت سیستم زیاد ازش استفاده میشه.
دمویی نیم ساعته در مورد مباحث مختلف امنیت و سطوح دسترسی در SharePoint
پس از دریافت پسوند فایل را به mp4 تغییر دهید.