نظرات مطالب
راهنمای گام به گام انتقال پروژه از MVC 5 به MVC 6
آیا کتابخانه‌های مربوطه در فایل project.json به درستی تعریف شده اند؟ اگر این طور است روی پوشه‌ی References کلیک راست و گزینه‌ی Restore Packages را انتخاب کنید. در زمان ریستور کردن چه پیغام خطایی دریافت میکنید؟ (در پنجره‌ی output)

یک بار هم این کار را انجام دهید: تمامی package‌ها را از فایل project.json پاک نمایید. فایل را ذخیره نمایید. vs را ببندید. کش nuget را از مسیر %LOCALAPPDATA%\NuGet\Cache\ پاک کنید. پروژه را دوباره باز نمایید و بسته‌ها را یکی یکی اضافه نمایید.  
نظرات مطالب
چگونه در یک پروژه سورس باز مشارکت کنیم؟
سلام؛ من دوست دارم یک پروژه اپن سورس رو در اینترنت قرار بدهم. علاقه شخصی ام این است که آن را در سایت خودم قرار بدم.آیا الزاما باید نرم افزارهای اپن سورس در سیستم‌های سورس کنترل مانند Git منتشر شوند یا الزامی خاصی در این موضوع وجود ندارد. مثلا من می‌خواهم فعلا پروژه را در یک وبلاگ قرار دهم و با کامنت گذاری علاقه مندان نظرات آن‌ها را هم در پروژه اعمال کنم.
مطالب
Scaffolding در EF Core
ایجاد Model  از روی Database موجود در EF Core

در بسیاری اوقات ممکن است تیم تحلیل دیتابیس، از توسعه اپلیکیشن جدا شده باشد تا مراحل نرمال سازی و تست بهره وری اجرای کوئری‌ها، به‌صورت جداگانه‌ای از توسعه‌ی برنامه انجام شود؛ یا ممکن است دیتابیس یک برنامه‌ی از پیش موجود، برای نگهداری و مهندسی مجدد به شما سپرده شود. سناریو هر چه باشد، جهت سرعت بخشیدن به توسعه‌ی نرم افزار میتوان از Entity Framework Core جهت ایجاد فایل‌های Model  از روی دیتابیس موجود استفاده کرد.

در این مثال ، از دیتابیس SQL Server  و یک برنامه‌ی کنسول و همچنین از ابزار NET Core CLI. استفاده خواهیم کرد.
با استفاده از ابزار CLI  ابتدا یک فولدر خالی به نام EfCoreDbToModel  ایجاد میکنیم:
> mkdir EfCoreDbToModel
سپس وارد این فولدر شده:
> cd EfCoreDbToModel
و بعد از آن یک پروژه‌ی جدید کنسول را در این فولدر ایجاد مینماییم:
> dotnet new console
 پس از مشاهده پیام Restore Succeeded، بسته‌های زیر را به پروژه اضافه میکنیم:
> dotnet add package Microsoft.EntityFrameworkCore.SqlServer
> dotnet add package Microsoft.EntityFrameworkCore.Tools
> dotnet add package Microsoft.EntityFrameworkCore.SqlServer.Design
بسته‌ی اول SQL Server Provider مناسب برای Entity Framework Core هست. بسته‌ی دوم مدیریت دستورات Entity Framework Core، از جمله دستورات Scaffold-DbContxet ،  Add-Migration  و Update-Database را بر عهده خواهد داشت. هر دو بسته‌ی فوق جهت ارتباط EF Core  با SQL Server  ضروری هستند و در نهایت جهت دسترسی به امکانات  ( Design-Time )  زمان طراحیِ  EF Core در SQL Server از جمله Scaffold کردن Model، به بسته‌ی سوم نیازمندیم.

در ادامه فایل csproj. را باز کرده و در صورتیکه خط زیر در آن موجود نیست، آن را به گره ItemGroup  اضافه کنید:
 < DotNetCliToolReference Include= " Microsoft.EntityFrameworkCore.Tools.DotNet " Version= " 2.0.0 " />
سپس بسته‌ها را Restore  نمایید:
> dotnet restore

اکنون با اجرای دستوری مثل دستور زیر، بررسی کنید که آیا دستورات Ef Core در دسترس هستند یا خیر:
> dotnet ef -h
در صورتیکه همه چیز مطابق انتظار کار کرده باشد، باید نتیجه‌ای مشابه تصویر زیر نمایش داده شود:


برای تولید فایل‌های Model، از دستور dbContext scaffold بصورت زیر استفاده میکنیم:
>dotnet ef dbcontext scaffold "Server=.;Database=Your_DB;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -o Model
دستور فوق دارای دو آرگومان اصلی است:
  1- Connection String
  2- Provider که Entity Framework Core Provider مخصوص دیتابیس مدنظر شماست.

لیستی از دیتابیس‌های مورد پشتیبانی EF Core را میتوانید در اینجا مشاهده کنید.

پس از اجرای دستور فوق، فولدر Model، شامل فایل‌های Entity و همچنین یک فایل دیگر که معرف DbContext است، ایجاد خواهند شد:


  گزینه‌ی o- دایرکتوری ایجاد فایل‌های مدل و DbContext را مشخص می‌کند. در صورتیکه از وارد کردن آن صرف نظر کنید، این فایل‌ها بصورت پیش فرض در مسیری قرار خواهند گرفت که فایل csproj. وجود دارد.
همانطور که ملاحظه میکنید نام کلاس DbContext از ترکیب نام دیتابیس بعلاوه‌ی کلمه “Context” خواهد بود. جهت تغییر نام این کلاس می‌توانید از گزینه‌ی "context "Your_Context_Title- استفاده نمائید. برای مثال:
> dotnet ef dbcontext scaffold "Server=.\;Database=Your_Db_name;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -o Model -context "MyDbContext"

جهت کسب اطلاعات بیشتر رجوع کنید به ^ و ^.
مطالب دوره‌ها
نگهداری سرور RavenDB
نگهداری سرور RavenDB شامل مواردی است مانند مدیریت فایل‌های آن، اضافه کردن یا حذف بانک‌های اطلاعاتی و تهیه پشتیبان از آن‌ها که در ادامه بررسی خواهند شد.


ایجاد و حذف بانک‌های اطلاعاتی جدید

برای این منظور به آدرس http://localhost:8080 مراجعه و از طریق کنسول مدیریتی تحت وب RavenDB بر روی دکمه New database کلیک کنید.


در صفحه باز شده می‌توان نام دیتابیس را مشخص کرد و همچنین در صورت نیاز افزونه‌هایی مانند فشرده سازی یا رمزنگاری اطلاعات را نیز فعال نمود.


پس از ایجاد دیتابیس، برای حذف آن، بر روی نام دیتابیس کلیک راست کرده و گزینه Delete را انتخاب کنید


روش دیگر حذف اطلاعات یک بانک اطلاعاتی، مراجعه به سندهای آن و سپس کلیک راست بر روی گروهی از آن‌ها برای حذف می‌باشد:


و یا سرور RavenDB را خاموش یا stop کنید. سپس به پوشه Database کنار فایل Raven.Server.exe مراجعه کرده، بانک اطلاعاتی خود را یافته و سپس کل پوشه آن‌را Delete کنید.


سؤال: چگونه با دیتابیس‌های ایجاد شده کار کنیم؟

تاکنون تمام مثال‌های برنامه با بانک اطلاعاتی پیش فرض RavenDB کار کردند (چیزی شبیه به master database در اس کیوال سرور) و هیچگاه ابتدا یک دیتابیس جدید و مستقل را برای انجام آزمایشات خود، ایجاد نکردیم. بدیهی است این روش برای محیط‌های کاری توصیه نمی‌شود.


برای نمونه در اینجا به System database این مجموعه وارد شده‌ایم که تعریف جزئیات بانک اطلاعاتی جدید ایجاد شده را در خود دارد.

جهت استفاده از بانک اطلاعاتی جدید ایجاد شده در کدهای خود، فقط کافی است خاصیت DefaultDatabase یک DocumentStore مقدار دهی شود:
 using (var store = new DocumentStore
{
    Url = "http://localhost:8080",
    DefaultDatabase = "Test2"
}.Initialize())
{
  //...
}


تهیه پشتیبان از بانک‌های اطلاعاتی و بازیابی آن‌ها

ابتدا نیاز است تمام بسته‌های مورد نیاز را یکجا از آدرس http://ravendb.net/download تهیه کنید. سپس به پوشه backup آن مراجعه کرده و از فایل اجرایی Raven.Backup.exe آن می‌توان جهت تهیه پشتیبان از بانک اطلاعاتی خاصی استفاده نمود. لازم به ذکر است که این برنامه باید با سطح دسترسی ادمین اجرا شود.
 Raven.Backup.exe --url==http://localhost:8080 --dest=d:\backup
برنامه backup، آدرس سرور را گرفته و سپس فایل‌های پشتیبان تهیه شده را در آدرس مشخصی ذخیره می‌کند. برای مدیریت اجرای روزانه آن نیز از برنامه استاندارد windows task schedule manager استفاده نمائید. به علاوه امکانات Shadow copy ویندوز نیز در اینجا مفید خواهند بود.

برای بازیابی و Restore یک بانک اطلاعاتی ابتدا دستور Raven.Server.exe /help را صادر کنید تا کلیه سوئیچ‌های این برنامه مشخص شوند. یکی از آن‌ها Restore نام دارد که پارامترهای dest و src را دریافت می‌کند (کجا بازیابی شود و از کجا اطلاعات را بخواند).

همچنین بجای backup و restore، امکان export و import نیز وجود دارند و برای انجام آن از برنامه Raven.Smuggler.exe که کنار Raven.Server.exe قرار دارد، می‌توان استفاده کرد.
برای تهیه خروجی (که در حقیقت تهیه یک dump فشرده شده از اسناد JSON موجود است):
 Raven.Smuggler.exe out http://localhost:8080/ dump.raven
و برای بازیابی خروجی تولید شده:
 Raven.Smuggler.exe in http://localhost:8080/ dump.raven
پروژه‌ها
DNTViewer
برنامه سورس باز DNTViewer، مشاهده‌گر آفلاین اطلاعات فایل دیتابیس سایت جاری است که با فرمت XML از آدرس ذیل قابل دریافت می‌باشد:



برای استفاده از آن نیاز به نصب دات نت فریم ورک 4 بر روی سیستم شما است. همچنین فایل XML بانک اطلاعاتی سایت را پس از دریافت نیاز است در کنار فایل EXE برنامه کپی کنید.
مطالب
ارسال ویدیو بصورت Async توسط Web Api
فریم ورک ASP.NET Web API صرفا برای ساخت سرویس‌های ساده‌ای که می‌شناسیم، نیست و در واقع مدل جدیدی برای برنامه نویسی HTTP است. کارهای بسیار زیادی را می‌توان توسط این فریم ورک انجام داد که در این مقاله به یکی از آنها می‌پردازم. فرض کنید می‌خواهیم یک فایل ویدیو را بصورت Asynchronous به کلاینت ارسال کنیم.

ابتدا پروژه جدیدی از نوع ASP.NET Web Application بسازید و قالب آن را MVC + Web API انتخاب کنید.


ابتدا به فایل WebApiConfig.cs در پوشه App_Start مراجعه کنید و مسیر پیش فرض را حذف کنید. برای مسیریابی سرویس‌ها از قابلیت جدید Attribute Routing استفاده خواهیم کرد. فایل مذکور باید مانند لیست زیر باشد.
public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services

        // Web API routes
        config.MapHttpAttributeRoutes();
    }
}
حال در مسیر ریشه پروژه، پوشه جدیدی با نام Videos ایجاد کنید و یک فایل ویدیو نمونه بنام sample.mp4 در آن کپی کنید. دقت کنید که فرمت فایل ویدیو در مثال جاری mp4 در نظر گرفته شده اما به سادگی می‌توانید آن را تغییر دهید.
سپس در پوشه Models کلاس جدیدی بنام VideoStream ایجاد کنید. این کلاس مسئول نوشتن داده فایل‌های ویدیویی در OutputStream خواهد بود. کد کامل این کلاس را در لیست زیر مشاهده می‌کنید.
public class VideoStream
{
    private readonly string _filename;
    private long _contentLength;

    public long FileLength
    {
        get { return _contentLength; }
    }

    public VideoStream(string videoPath)
    {
        _filename = videoPath;
        using (var video = File.Open(_filename, FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            _contentLength = video.Length;
        }
    }

    public async void WriteToStream(Stream outputStream,
        HttpContent content, TransportContext context)
    {
        try
        {
            var buffer = new byte[65536];

            using (var video = File.Open(_filename, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                var length = (int)video.Length;
                var bytesRead = 1;

                while (length > 0 && bytesRead > 0)
                {
                    bytesRead = video.Read(buffer, 0, Math.Min(length, buffer.Length));
                    await outputStream.WriteAsync(buffer, 0, bytesRead);
                    length -= bytesRead;
                }
            }
        }
        catch (HttpException)
        {
            return;
        }
        finally
        {
            outputStream.Close();
        }
    }
}

شرح کلاس VideoStream
این کلاس ابتدا دو فیلد خصوصی تعریف می‌کند. یکی filename_ که فقط-خواندنی است و نام فایل ویدیو درخواستی را نگهداری می‌کند. و دیگری contentLength_ که سایز فایل ویدیو درخواستی را نگهداری می‌کند.

یک خاصیت عمومی بنام FileLength نیز تعریف شده که مقدار خاصیت contentLength_ را بر می‌گرداند.

متد سازنده این کلاس پارامتری از نوع رشته بنام videoPath را می‌پذیرد که مسیر کامل فایل ویدیوی مورد نظر است. در این متد، متغیر‌های filename_ و contentLength_ مقدار دهی می‌شوند. نکته‌ی قابل توجه در این متد استفاده از پارامتر FileShare.Read است که باعث می‌شود فایل مورد نظر هنگام باز شدن قفل نشود و برای پروسه‌های دیگر قابل دسترسی باشد.

در آخر متد WriteToStream را داریم که مسئول نوشتن داده فایل‌ها به OutputStream است. اول از همه دقت کنید که این متد از کلمه کلیدی async استفاده می‌کند بنابراین بصورت asynchronous اجرا خواهد شد. در بدنه این متد متغیری بنام buffer داریم که یک آرایه بایت با سایز 64KB را تعریف می‌کند. به بیان دیگر اطلاعات فایل‌ها را در پکیج‌های 64 کیلوبایتی برای کلاینت ارسال خواهیم کرد. در ادامه فایل مورد نظر را باز می‌کنیم (مجددا با استفاده از FileShare.Read) و شروع به خواندن اطلاعات آن می‌کنیم. هر 64 کیلوبایت خوانده شده بصورت async در جریان خروجی نوشته می‌شود و تا هنگامی که به آخر فایل نرسیده ایم این روند ادامه پیدا می‌کند.
while (length > 0 && bytesRead > 0)
{
    bytesRead = video.Read(buffer, 0, Math.Min(length, buffer.Length));
    await outputStream.WriteAsync(buffer, 0, bytesRead);
    length -= bytesRead;
}
اگر دقت کنید تمام کد بدنه این متد در یک بلاک try/catch قرار گرفته است. در صورتی که با خطایی از نوع HttpException مواجه شویم (مثلا هنگام قطع شدن کاربر) عملیات متوقف می‌شود و در آخر نیز جریان خروجی (outputStream) بسته خواهد شد. نکته دیگری که باید بدان اشاره کرد این است که کاربر حتی پس از قطع شدن از سرور می‌تواند ویدیو را تا جایی که دریافت کرده مشاهده کند. مثلا ممکن است 10 پکیج از اطلاعات را دریافت کرده باشد و هنگام مشاهده پکیج دوم از سرور قطع شود. در این صورت امکان مشاهده ویدیو تا انتهای پکیج دهم وجود خواهد داشت.

حال که کلاس VideoStream را در اختیار داریم می‌توانیم پروژه را تکمیل کنیم. در پوشه کنترلر‌ها کلاسی بنام VideoControllerبسازید. کد کامل این کلاس را در لیست زیر مشاهده می‌کنید.
public class VideoController : ApiController
{
    [Route("api/video/{ext}/{fileName}")]
    public HttpResponseMessage Get(string ext, string fileName)
    {
        string videoPath = HostingEnvironment.MapPath(string.Format("~/Videos/{0}.{1}", fileName, ext));
        if (File.Exists(videoPath))
        {
            FileInfo fi = new FileInfo(videoPath);
            var video = new VideoStream(videoPath);

            var response = Request.CreateResponse();

            response.Content = new PushStreamContent((Action<Stream, HttpContent, TransportContext>)video.WriteToStream,
                new MediaTypeHeaderValue("video/" + ext));

            response.Content.Headers.Add("Content-Disposition", "attachment;filename=" + fi.Name.Replace(" ", ""));
            response.Content.Headers.Add("Content-Length", video.FileLength.ToString());

            return response;
        }
        else
        {
            return Request.CreateResponse(HttpStatusCode.NotFound);
        }
    }
}

شرح کلاس VideoController
همانطور که می‌بینید مسیر دستیابی به این کنترلر با استفاده از قابلیت Attribute Routing تعریف شده است.

[Route("api/video/{ext}/{fileName}")]
نمونه ای از یک درخواست که به این مسیر نگاشت می‌شود:
api/video/mp4/sample
بنابراین این مسیر فرمت و نام فایل مورد نظر را بدین شکل می‌پذیرد. در نمونه جاری ما فایل sample.mp4 را درخواست کرده ایم.
متد Get این کنترلر دو پارامتر با نام‌های ext و fileName را می‌پذیرد که همان فرمت و نام فایل هستند. سپس با استفاده از کلاس HostingEnvironment سعی می‌کنیم مسیر کامل فایل درخواست شده را بدست آوریم.
string videoPath = HostingEnvironment.MapPath(string.Format("~/Videos/{0}.{1}", fileName, ext));
استفاده از این کلاس با Server.MapPath تفاوتی نمی‌کند. در واقع خود Server.MapPath نهایتا همین کلاس HostingEnvironment را فراخوانی می‌کند. اما در کنترلر‌های Web Api به کلاس Server دسترسی نداریم. همانطور که مشاهده می‌کنید فایل مورد نظر در پوشه Videos جستجو می‌شود، که در ریشه سایت هم قرار دارد. در ادامه اگر فایل درخواست شده وجود داشت وهله جدیدی از کلاس VideoStream می‌سازیم و مسیر کامل فایل را به آن پاس می‌دهیم.
var video = new VideoStream(videoPath);
سپس آبجکت پاسخ را وهله سازی می‌کنیم و با استفاده از کلاس PushStreamContent اطلاعات را به کلاینت می‌فرستیم.
var response = Request.CreateResponse();

response.Content = new PushStreamContent((Action<Stream, HttpContent, TransportContext>)video.WriteToStream, new MediaTypeHeaderValue("video/" + ext));

کلاس PushStreamContent در فضای نام System.Net.Http وجود دارد. همانطور که می‌بینید امضای Action پاس داده شده، با امضای متد WriteToStream در کلاس VideoStream مطابقت دارد.

در آخر دو Header به پاسخ ارسالی اضافه می‌کنیم تا نوع داده ارسالی و سایز آن را مشخص کنیم.
response.Content.Headers.Add("Content-Disposition", "attachment;filename=" + fileName);
response.Content.Headers.Add("Content-Length", video.FileLength.ToString());
افزودن این دو مقدار مهم است. در صورتی که این Header‌‌ها را تعریف نکنید سایز فایل دریافتی و مدت زمان آن نامعلوم خواهد بود که تجربه کاربری خوبی بدست نمی‌دهد. نهایتا هم آبجکت پاسخ را به کلاینت ارسال می‌کنیم. در صورتی هم که فایل مورد نظر در پوشه Videos پیدا نشود پاسخ NotFound را بر می‌گردانیم.
if(File.Exists(videoPath))
{
    // removed for bravity
}
else
{
    return Request.CreateResponse(HttpStatusCode.NotFound);
}
خوب، برای تست این مکانیزم نیاز به یک کنترلر MVC و یک View داریم. در پوشه کنترلر‌ها کلاسی بنام HomeController ایجاد کنید که با لیست زیر مطابقت داشته باشد.
public class HomeController : Controller
{
    // GET: Home
    public ActionResult Index()
    {
        return View();
    }
}
نمای این متد را بسازید (با کلیک راست روی متد Index و انتخاب گزینه Add View) و کد آن را مطابق لیست زیر تکمیل کنید.
<div>
    <div>
        <video width="480" height="270" controls="controls" preload="auto">
            <source src="/api/video/mp4/sample" type="video/mp4" />
            Your browser does not support the video tag.
        </video>
    </div>
</div>
همانطور که مشاهده می‌کنید یک المنت ویدیو تعریف کرده ایم که خواص طول، عرض و غیره آن نیز مقدار دهی شده اند. زیر تگ source متنی درج شده که در صورت لزوم به کاربر نشان داده می‌شود. گرچه اکثر مرورگرهای مدرن از المنت ویدیو پشتیبانی می‌کنند. تگ سورس فایلی با مشخصات sample.mp4 را درخواست می‌کند و نوع آن را نیز video/mp4 مشخص کرده ایم.

اگر پروژه را اجرا کنید می‌بینید که ویدیو مورد نظر آماده پخش است. برای اینکه ببینید چطور داده‌های ویدیو در قالب پکیج‌های 64 کیلو بایتی دریافت می‌شوند از ابزار مرورگرتان استفاده کنید. مثلا در گوگل کروم F12 را بزنید و به قسمت Network بروید. صفحه را یکبار مجددا بارگذاری کنید تا ارتباطات شبکه مانیتور شود. اگر به المنت sample دقت کنید می‌بینید که با شروع پخش ویدیو پکیج‌های اطلاعات یکی پس از دیگری دریافت می‌شوند و اطلاعات ریز آن را می‌توانید مشاهده کنید.

پروژه نمونه به این مقاله ضمیمه شده است. قابلیت Package Restore فعال شده و برای صرفه جویی در حجم فایل، تمام پکیج‌ها و محتویات پوشه bin حذف شده اند. برای تست بیشتر می‌توانید فایل sample.mp4 را با فایلی حجیم‌تر جایگزین کنید تا نحوه دریافت اطلاعات را با روشی که در بالا بدان اشاره شد مشاهده کنید.

AsyncVideoStreaming.rar  
پاسخ به بازخورد‌های پروژه‌ها
مشکل دریافتن محل دریافت فایل‌ها
- در این سایت در قسمت پروژه‌ها، هر پروژه یک صفحه اصلی و معرفی دارد. در کنار این صفحه، سمت راست آن، یک منوی دریافت فایل هست. از اینجا سورس یا فایل‌های مرتبط با پروژه جاری قابل دریافت هستند.



- کلمه عبور و نام کاربری داده شده مربوط به زمانی است که سورس پروژه دریافتی رو در VS.NET اجرا کردید (حتما یکبار نظرات پیشین رو هم برای دریافت پیشنیازها مطالعه کنید) و قصد دارید مثلا به برنامه لاگین کنید.
مطالب
تهیه یک Clone از مخزن کدی در گوگل کد

برای مثال پروژه "unhaddins" را در نظر بگیرید. این پروژه یک سری افزونه را جهت کار ساده‌تر با NHibernate ارائه داده است. برای مثال چگونه با WPF یا WCF و امثال آن بتوان به سادگی با NHibernate ارتباط برقرار کرد. این پروژه خروجی قابل دریافتی ندارد؛ به عبارتی یک سری سورس کد است. دریافت یک مخزن کد هم که از گوگل کد در این سمت مشکل است ... اما راه بهتری هم وجود دارد. یکی از خواص کار با سورس کنترل‌ها، امکان تهیه یک clone از یک مخزن کد است. تمام پروژه‌های موجود در گوگل کد هم به این شکل با SVN در دسترس هستند:
http://someproject.googlecode.com/svn/trunk/
که به جای someproject ، نام پروژه مورد نظر قرار خواهد گرفت.

برای نمونه، در سایت https://bitbucket.org ثبت نام کنید. سپس گزینه ایجاد یک مخزن جدید را انتخاب کرده:



و در صفحه‌ی باز شده، گزینه‌ی Import from Subversion را انتخاب کنید:



در اینجا Url خواسته شده باید شبیه به همان آدرس trunk فوق باشد و اگر تیک private فعال باشد (که هست)،‌ دیگران امکان دسترسی به مخزن کد شما را نخواهند داشت. البته این تنظیم پس از دریافت، در برگه‌ی Admin مخزن ایجاد شده نیز قابل تغییر است.

به علاوه سایت github.com هم هر چند بر اساس Git کار می‌کند، اما امکان تهیه یک کپی مطابق اصل از یک مخزن کد SVN را هم دارد؛ به شرح زیر:

یک اکانت رایگان در GitHub درست کنید. بعد یک مخزن خالی جدید را ایجاد کرده و در همان صفحه روی لینک Import a Subversion Repository کلیک کنید و آدرس svn مورد نظر را بدهید.

البته GitHub در دریافت پروژه unhaddins موفق عمل نکرد، اما bitbucket خیلی سریع کل آن‌را دریافت نمود.