مطالب
استفاده از لنگر (anchor) برای اسکرول به قسمت خاصی از صفحه در Blazor Server
فرض کنید کدی مانند زیر را در یک کامپوننت داریم و انتظار این است که با کلیک بر روی Section2، به بخش مورد نظر اسکرول شویم:
@page "/test"

<nav>
    <!-- یک روش -->
    <a href="#section2">Section2</a>

    <!-- روش دیگر -->
    <NavLink href="#section2">Section2</NavLink>    
</nav>

@* ... *@


<h2 id="section2">It's Section2.</h2>
@* ... *@
اما متاسفانه در Blazor Server تا نسخه فعلی آن (نسخه هفت)، این کار ساده به راحتی امکان‌پذیر نیست. همانطور که ملاحظه می‌کنید، به دو روش، نویگیشن انجام شده‌است؛ اما هیچ‌یک ما را به هدف نمی‌رسانند. دلیل این موضوع، رفتار Blazor Server در بارگذاری صفحات می‌باشد. در حقیقت المان‌ها موقع بارگذاری، هنوز در صفحه وجود ندارند. در واقع ابتدا نیاز است که اتصال SignalR برقرار شود و سپس داده‌ها از سرور دریافت شوند (مگر در حالت pre-rendered که مشکلات خاص خود را در پی دارد).
برای انجام این کار دو روش وجود دارد؛ یکی بر پایه‌ی جاوااسکریپت است و دیگری توسط توابع داخلی Blazor JS.


روش جاوااسکریپتی

ابتدا یک کامپوننت را به نام AnchorNavigation ایجاد می‌نماییم:
@inject IJSRuntime JSRuntime
@inject NavigationManager NavigationManager
@implements IDisposable
@code {
    protected override void OnInitialized()
    {
        NavigationManager.LocationChanged += OnLocationChanged;
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        await ScrollToFragment();
    }

    public void Dispose()
    {
        NavigationManager.LocationChanged -= OnLocationChanged;
    }

    private async void OnLocationChanged(object sender, LocationChangedEventArgs e)
    {
        await ScrollToFragment();
    }

    private async Task ScrollToFragment()
    {
        var uri = new Uri(NavigationManager.Uri, UriKind.Absolute);
        var fragment = uri.Fragment;
        if (fragment.StartsWith('#'))
        {
            // Handle text fragment (https://example.org/#test:~:text=foo)
            // https://github.com/WICG/scroll-to-text-fragment/
            var elementId = fragment.Substring(1);
            var index = elementId.IndexOf(":~:", StringComparison.Ordinal);
            if (index > 0)
            {
                elementId = elementId.Substring(0, index);
            }

            if (!string.IsNullOrEmpty(elementId))
            {
                await JSRuntime.InvokeVoidAsync("BlazorScrollToId", elementId);
            }
        }
    }
}
سپس کد جاوا اسکریپتی زیر را در جایی قبل از فراخوانی <script src="_framework/blazor.server.js"></script> قرار می‌دهیم (برای مثال اگر می‌خواهیم در اکثر صفحات از آن بهره ببریم، آن را در layout.cshtmlـ قرار می‌دهیم).
function BlazorScrollToId(id) {
            const element = document.getElementById(id);
            if (element instanceof HTMLElement) {
                element.scrollIntoView({
                    behavior: "smooth",
                    block: "start",
                    inline: "nearest"
                });
            }
        }
حال در هر کامپوننتی که نیاز به استفاده از لنگر (anchor) داریم، به شکل زیر عمل می‌کنیم:
@page "/"

<PageTitle>Index</PageTitle>

<a href="#section2">
    <h1>Section2</h1>
</a>

<SurveyPrompt Title="How is Blazor working for you?" />

<div style="height: 2000px">

</div>

<div id="section2">
    <h2>It's Section2. </h2>
</div>

<AnchorNavigation />


روش استفاده از توابع داخلی Blazor JS 

می توان از ElementReference و FocusAsync که در حقیقت مربوط به خود Blazor JS می‌باشند استفاده نمود. اینبار کدهای کامپوننت AnchorNavigation را به شکل زیر تغییر می‌دهیم:
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Rendering;
using Microsoft.AspNetCore.Components.Routing;
using System.Diagnostics.CodeAnalysis;

namespace TestAnchorNavigation;

public class AnchorNavigation: ComponentBase, IDisposable
{
    private bool _setFocus;

    [Inject] private NavigationManager NavManager { get; set; } = default!;
    [Parameter] public RenderFragment? ChildContent { get; set; }
    [Parameter] public string? BookmarkName { get; set; }
    [DisallowNull] public ElementReference? Element { get; private set; }

    protected override void BuildRenderTree(RenderTreeBuilder builder)
    {
        builder.OpenElement(0, "span");
        builder.AddAttribute(2, "tabindex", "-1");
        builder.AddContent(3, this.ChildContent);
        builder.AddElementReferenceCapture(4, this.SetReference);
        builder.CloseElement();
    }

    protected override void OnInitialized()
        => NavManager.LocationChanged += this.OnLocationChanged;

    protected override void OnParametersSet()
        => _setFocus = this.IsMe();

    private void SetReference(ElementReference reference)
        => this.Element = reference;

    private void OnLocationChanged(object? sender, LocationChangedEventArgs e)
    {
        if (this.IsMe())
        {
            _setFocus = true;
            this.StateHasChanged();
        }
    }

    protected async override Task OnAfterRenderAsync(bool firstRender)
    {
        if (_setFocus)
            await this.Element!.Value.FocusAsync(false);

        _setFocus = false;
    }

    private bool IsMe()
    {
        string? elementId = null;

        var uri = new Uri(this.NavManager.Uri, UriKind.Absolute);
        if (uri.Fragment.StartsWith('#'))
        {
            elementId = uri.Fragment.Substring(1);
            return elementId == BookmarkName;
        }
        return false;
    }

    public void Dispose()
        => NavManager.LocationChanged -= this.OnLocationChanged;
}
و پیرو آن، صفحه‌ی موردنظر برای استفاده از لنگر نیز به شکل زیر تغییر خواهد کرد:
@page "/"

<PageTitle>Index</PageTitle>

<NavLink href="#section2">
    <h1>Section2</h1>
</NavLink>

<SurveyPrompt Title="How is Blazor working for you?" />

<div style="height: 2000px">

</div>

<AnchorNavigation BookmarkName="section2">
      <h2>It's Section2. </h2>
</AnchorNavigation>
مطالب دوره‌ها
کار با فرم‌ها در بوت استرپ 3
در مطلب «استفاده از Twitter Bootstrap در کارهای روزمره طراحی وب» به نکات مرتبط با کار با فرم‌ها در بوت استرپ 2 پرداخته شد. همچنین مطالبی مانند «ویرایش قالب پیش فرض Add View در ASP.NET MVC برای سازگار سازی آن با Twitter bootstrap» برای خودکار سازی تولید فرم‌های بوت استرپ 2 در برنامه‌های ASP.NET MVC و نکات «اعمال کلاس‌های ویژه اعتبارسنجی Twitter bootstrap به فرم‌های ASP.NET MVC» نیز بررسی شدند. در بوت استرپ 3، بسیاری از این نکات تغییر کرده‌اند و نیاز است با نحوه ارتقاء فرم‌های بوت استرپ 2 به 3 و کلا نحوه کار با فرم‌ها در بوت استرپ 3 بیشتر آشنا شد.


نحوه ارتقاء فرم‌های بوت استرپ 2 به 3

تمام این تغییرات در بوت استرپ 3، جهت پیاده سازی ایده mobile-first بودن آن است. برای مثال فرم‌های افقی بوت استرپ 3 با کوچک شدن اندازه صفحه، به صورت خودکار واکنش نشان داده و تبدیل به فرم‌های معمولی که اجزای آن به صورت یک stack عمودی قرار گرفته‌اند، می‌شوند.
اکنون اگر فرم‌هایی را دارید که در برنامه‌های پیشین خود از بوت استرپ 2 استفاده کرده‌اند، نیاز است تغییرات ذیل را به آن‌ها اعمال کنید تا با سیستم جدید بوت استرپ 3 سازگار شوند:

- کلاس control-group را به کلاس form-group تبدیل کنید.
- form-search حذف شده است. آن‌را با form-inline جایگزین کنید.
- دیگر نیازی به استفاده از input-block-level نیست؛ از آنجائیکه به صورت پیش فرض کلیه inputها دارای عرض 100 درصد هستند.
- help-inline حذف شده است. آن‌را با help-block جایگزین کنید.
- عرض ستون‌ها را در فرم‌های افقی، برچسب‌ها و کنترل‌ها مشخص کنید.
- کلاس controls حذف شده است.
- کلاس form-control را به inputها و selectها اضافه کنید.
- checkboxها و radioها باید در یک div محصور شوند.
- کلاس‌های radio.inline و checkbox.inline باید با inline جایگزین شوند.
- کلاس‌های input-small به input-sm و input-large به input-lg تبدیل شده‌اند.
- کلاس‌های input-prepend با input-group و input-append با input-group جایگزین شده‌اند.
- کلاس alert-error حذف شده‌است. بجای آن می‌شود از alert-warning استفاده کرد.
- کلاس alert-block را با alert جایگزین کنید.


ایجاد اولین فرم افقی با بوت استرپ 3

فرض کنید که قصد داریم یک چنین فرم افقی را توسط امکانات بوت استرپ 3 ایجاد کنیم:



همانطور که ملاحظه می‌کنید، با کوچک شدن اندازه صفحه، این فرم نیز تغییر شکل می‌دهد:



کدهای کامل این فرم را در ادامه ملاحظه می‌کنید:
    <div class="container">
        <h4 class="alert alert-info">
            فرم‌های بوت استرپ 3</h4>
        <div class="row">
            <article class="registrationform">
                <h2>
                    فرم ثبت نام</h2>               
                <form class="registration form-horizontal" action="#">
                <fieldset id="personalinfo">
                    <legend>اطلاعات شخصی</legend>
                    <section class="row">
                        <label class="col col-lg-4 control-label" for="myname">
                            نام</label>
                        <div class="controls">
                            <input class="col col-lg-8" type="text" name="myname" 
                                   id="myname" autofocus placeholder="نام و نام خانوادگی"
                                   required>
                        </div>
                        <!-- controls -->
                    </section><!-- row -->
                    <section class="row">
                        <label class="col col-lg-4 control-label" for="companyname">
                            نام شرکت</label>
                        <div class="controls">
                            <input class="col col-lg-8" type="text" name="companybname" id="companyname" />
                        </div>
                        <!-- controls -->
                    </section><!-- row -->
                    <section class="row">
                        <label class="col col-lg-4 control-label" for="myemail">
                            ایمیل</label>
                        <div class="controls">
                            <input class="col col-lg-8" type="email" name="myemail" id="myemail" 
                                   required autocomplete="off" />
                        </div>
                        <!-- controls -->
                    </section><!-- row -->
                </fieldset>
                <!-- personal info -->
                <fieldset id="otherinfo">
                    <legend>سایر اطلاعات</legend>
                    <section class="row">
                        <label class="col col-lg-4 control-label">
                            نوع درخواست</label>
                        <div class="controls col col-lg-8">
                            <label class="radio">
                                <input type="radio" name="requesttype" value="question" />
                                سؤال
                            </label>
                            <label class="radio">
                                <input type="radio" name="requesttype" value="comment" />
                                انتقاد
                            </label>
                        </div>
                        <!-- controls -->
                    </section><!-- row -->
                    <section class="row">
                        <label class="col col-lg-4 control-label">
                            خبرنامه</label>
                        <div class="controls col col-lg-8">
                            <label class="checkbox">
                                <input type="checkbox" id="subscribe" name="subscribe" checked value="yes" />
                               آیا مایل به دریافت ایمیل‌های خبرنامه ما هستید؟
                            </label>
                        </div>
                        <!-- controls -->
                    </section><!-- row -->
                    <section class="row">
                        <label class="col col-lg-4 control-label" for="reference">
                            چطور از وجود سایت ما آگاه شدید؟</label>
                        <div class="controls col col-lg-8">
                            <select name="reference" id="reference">
                                <option>لطفا انتخاب کنید...</option>
                                <option value="friend">از طریق یک دوست</option>
                                <option value="facebook">Facebook</option>
                                <option value="twitter">Twitter</option>
                            </select>
                        </div>
                        <!-- controls -->
                    </section><!-- row -->
                </fieldset>
                <button class="btn" type="submit">
                    ارسال</button>
                </form>
            </article>
        </div>
        <!-- end row -->
    </div>
    <!-- /container -->
توضیحات:

- باید درنظر داشت که اگر هیچگونه فرمتی را به فرم‌های بوت استرپ 3 اعمال نکنیم، به صورت پیش فرض فرمت دهی شده و تبدیل به فرم‌های عمودی شکیلی می‌شوند که شاید از دیدگاه خیلی‌ها مناسب بوده و نیاز به تغییرات خاصی نداشته باشند.
- برای تبدیل این فرم عمودی پیش فرض، به فرم‌های افقی دو ستونه، نیاز است یک سری کلاس بوت استرپ 3 را به المان‌های آن اضافه کنیم. برای این منظور ابتدا کلاس form-horizontal را به تگ فرم اضافه می‌کنیم.
- هر سطر فرم، در یک المان section با کلاس row قرار خواهد گرفت.
- اکنون هر سطر، از یک برچسب به همراه یک یا چند المان تشکیل خواهد شد. در هر سطر، کنترل‌ها در یک div با کلاس controls قرار می‌گیرند.
- برای اینکه برچسب‌های هر ردیف با کنترل‌ها و المان‌های آن ردیف، تراز شوند، تنها کافی است به آن‌ها کلاس control-label را اضافه کنیم.
در ادامه تمام این مراحل را باید به ازای هر سطر فرم تکرار کنیم.

- زمانیکه به radio buttons یا check boxes می‌رسیم، باید به چند نکته دقت داشت:
الف) حین کار با radio buttons، علاوه بر برچسب آن سطر که با label مشخص می‌شود، هر radio button نیز باید داخل یک label با کلاس radio محصور شود.
ب) تمام radio buttons یک سطر نیز باید در یک div ایی با کلاس controls محصور شوند.
این نکته در مورد check boxes نیز صادق است.

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



اصلاح قالب ایجاد فرم‌های خودکار ASP.NET MVC بر اساس بوت استرپ 3

مطلب «ویرایش قالب پیش فرض Add View در ASP.NET MVC برای سازگار سازی آن با Twitter bootstrap» جهت بوت استرپ 2 تهیه شده بود. فایل نهایی ویرایش شده آن‌را با توجه به توضیحات مطلب جاری برای بوت استرپ 3 از پیوست انتهای بحث دریافت کنید و برای استفاده از آن فقط کافی است آن‌را در مسیر CodeTemplates\AddView\CSHTML\CreateBootstrap3Form.tt ریشه پروژه جاری خود کپی و به پروژه اضافه کنید تا در صفحه دیالوگ Add view ظاهر شود (خاصیت custom tool آن‌را هم خالی کنید).


در مورد اعتبارسنجی‌های فرم‌ها چطور؟

اصلاح مطالبی مانند «اعمال کلاس‌های ویژه اعتبارسنجی Twitter bootstrap به فرم‌های ASP.NET MVC» جهت کار با فرم‌های بوت استرپ 3 بسیار ساده است. از این جهت که در کدهای آن فقط باید نام کلاس‌های CSS قدیمی به جدید ویرایش شوند. مابقی کدها یکسان است. مثلا نام کلاس control-group شده است form-group (همان توضیحات ابتدای بحث جاری). کلاس‌های error شده‌اند has-error و success شده است has-success.



فایل‌های نهایی این قسمت را از اینجا نیز می‌توانید دریافت کنید:
bs3-sample05.zip  
نظرات مطالب
ساخت دیتابیس sqlite با EF6 Code First
سلام مجدد
من از دات نت Core استفاده نمی‌کنم.
من مطابق زیر عمل کردم ولی بازم همان خطا را می‌دهد.
 the underlying provider failed to open
نمیدونم چرا تگ  Connection-string  را نمیشناسه. 
دقیقا در پروژه شما اگر تگ  Connection-string  را برداریم با چنین خطایی روبرو می‌شویم.
من پروژه تستی خودم را اینجا آپلود کردم.
کد XML فایل پروژه
<?xml version="1.0" encoding="utf-8"?>
<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=301880
  -->
<configuration>
  <configSections>
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
  </configSections>
  <appSettings>
    <add key="webpages:Version" value="3.0.0.0" />
    <add key="webpages:Enabled" value="false" />
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
  </appSettings>
  <connectionStrings>
    <add name="constr" connectionString="data source=.\phonebook.sqlite;foreign keys=true" providerName="System.Data.SQLite" />
  </connectionStrings>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
  </system.web>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <system.codedom>
    <compilers>
      <compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701" />
      <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+" />
    </compilers>
  </system.codedom>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="v13.0" />
      </parameters>
    </defaultConnectionFactory>
    <!--<providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>-->
    <providers>
      <provider invariantName="System.Data.SQLite" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" />
      <provider invariantName="System.Data.SQLite.EF6" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" />
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>
  <system.data>
    <DbProviderFactories>
      <remove invariant="System.Data.SQLite.EF6" />
      <add name="SQLite Data Provider (Entity Framework 6)" invariant="System.Data.SQLite.EF6" description=".NET Framework Data Provider for SQLite (Entity Framework 6)" type="System.Data.SQLite.EF6.SQLiteProviderFactory, System.Data.SQLite.EF6" />
      <remove invariant="System.Data.SQLite" />
      <add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".NET Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" />
    </DbProviderFactories>
  </system.data>
</configuration>
کد xml فایل Package
<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="bootstrap" version="3.0.0" targetFramework="net45" />
  <package id="EntityFramework" version="6.1.3" targetFramework="net45" />
  <package id="jQuery" version="1.10.2" targetFramework="net45" />
  <package id="Microsoft.AspNet.Mvc" version="5.2.3" targetFramework="net45" />
  <package id="Microsoft.AspNet.Razor" version="3.2.3" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebPages" version="3.2.3" targetFramework="net45" />
  <package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="1.0.0" targetFramework="net45" />
  <package id="Microsoft.Net.Compilers" version="1.0.0" targetFramework="net45" developmentDependency="true" />
  <package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net45" />
  <package id="Modernizr" version="2.6.2" targetFramework="net45" />
  <package id="SQLite.CodeFirst" version="1.3.0.17" targetFramework="net45" />
  <package id="System.Data.SQLite" version="1.0.105.0" targetFramework="net45" />
  <package id="System.Data.SQLite.Core" version="1.0.105.0" targetFramework="net45" />
  <package id="System.Data.SQLite.EF6" version="1.0.105.0" targetFramework="net45" />
  <package id="System.Data.SQLite.Linq" version="1.0.105.0" targetFramework="net45" />
</packages>

مابقی همون کلاس‌ها و کد‌های مثال آزمایشی شماست.
من انتظار دارم در لحظه اول در نبود Database.sqlte آن را ایجاد کند. ( مانند مثال شما )

مطالب
استفاده از LINQ to XML جهت خواندن فیدهای RSS

مثال زیر را به عنوانی نمونه‌ای از کاربرد LINQ to XML برای خواندن فیدهای RSS که اساسا به فرمت XML هستند می‌توان ارائه داد.
ابتدا کد کامل مثال را در نظر بگیرید:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

namespace LinqToRSS
{
public static class LanguageExtender
{
public static string SafeValue(this XElement input)
{
return (input == null) ? string.Empty : input.Value;
}

public static DateTime SafeDateValue(this XElement input)
{
return (input == null) ? DateTime.MinValue : DateTime.Parse(input.Value);
}
}

public class RssEntry
{
public string Title { set; get; }
public string Description { set; get; }
public string Link { set; get; }
public DateTime PublicationDate { set; get; }
public string Author { set; get; }
public string BlogName { set; get; }
public string BlogAddress { set; get; }
}

public class Rss
{
static XElement selectDate(XElement date1, XElement date2)
{
return date1 ?? date2;
}

public static List<RssEntry> GetEntries(string feedUrl)
{
//applying namespace in an XElement
XName xn = XName.Get("{http://purl.org/dc/elements/1.1/}creator");//{namespace}root
XName xn2 = XName.Get("{http://purl.org/dc/elements/1.1/}date");

var feed = XDocument.Load(feedUrl);
if (feed.Root == null) return null;

var items = feed.Root.Element("channel").Elements("item");
var feedQuery =
from item in items
select new RssEntry
{
Title = item.Element("title").SafeValue(),
Description = item.Element("description").SafeValue(),
Link = item.Element("link").SafeValue(),
PublicationDate =
selectDate(item.Element(xn2), item.Element("pubDate")).SafeDateValue(),
Author = item.Element(xn).SafeValue(),
BlogName = item.Parent.Element("title").SafeValue(),
BlogAddress = item.Parent.Element("link").SafeValue()
};

return feedQuery.ToList();
}
}

class Program
{
static void Main(string[] args)
{
List<RssEntry> entries = Rss.GetEntries("http://weblogs.asp.net/aspnet-team/rss.aspx");
if (entries != null)
foreach (var item in entries)
Console.WriteLine(item.Title);

Console.WriteLine("Press a key...");
Console.ReadKey();
}
}
}

توضیحات:
1- در این مثال فقط جهت سهولت بیان آن در یک صفحه، تمامی کلاس‌های تعریف شده در یک فایل آورده شدند. این روش صحیح نیست و باید به ازای هر کلاس یک فایل جدا در نظر گرفته شود.
2- کلاس LanguageExtender از قابلیت extension methods سی شارپ 3 استفاده می‌کند. به این صورت کلاس XElement دات نت بسط یافته و دو متد به آن اضافه می‌شود که به سادگی در کدهای خود می‌توان از آن‌ها استفاده کرد. هدف آن هم بررسی نال بودن یک آیتم دریافتی و ارائه‌ی حاصلی امن برای این مورد است.
3- کلاس RssEntry به جهت استفاده در خروجی کوئری LINQ تعریف شد. می‌خواهیم خروجی نهایی، یک لیست جنریک از نوع RssEntry باشد.
4- متد اصلی برنامه، GetEntries است. این متد آدرس اینترنتی یک فید را دریافت کرده و پس از آنالیز، آن‌را به صورت یک لیست بر می‌گرداند.

<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://weblogs.asp.net/utility/FeedStylesheets/rss.xsl" media="screen"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/">
<channel>
<title>Latest Microsoft Blogs</title>
<link>http://weblogs.asp.net/aspnet-team/default.aspx</link>
<description />
<dc:language>en</dc:language>
<generator>CommunityServer 2007 SP1 (Build: 20510.895)</generator>
<item>
<title>Comments on my recent benchmarks.</title>
<link>http://misfitgeek.com/blog/aspnet/comments-on-my-recent-benchmarks/</link>
<pubDate>Mon, 10 Aug 2009 23:33:59 GMT</pubDate>
<guid isPermaLink="false">c06e2b9d-981a-45b4-a55f-ab0d8bbfdc1c:7166225</guid>
<dc:creator>Misfit Geek: msft</dc:creator>
<slash:comments>0</slash:comments>
<wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://weblogs.asp.net/aspnet-team/rsscomments.aspx?PostID=7166225</wfw:commentRss>
<comments>http://misfitgeek.com/blog/aspnet/comments-on-my-recent-benchmarks/#comments</comments>
<description>Overall I’ve been pretty impressed ...</description>
<category domain="http://weblogs.asp.net/aspnet-team/archive/tags/ASP.NET/default.aspx">ASP.NET</category>
</item>
</channel>
</rss>
برای نمونه خروجی یک فید می‌تواند به صورت فوق باشد. آیتم‌های آن به صورت قابل بیان است:
var items = feed.Root.Element("channel").Elements("item");
و نکته مهمی که اینجا وجود دارد، اعمال فضاهای نام بکار رفته در این فایل xml پیشرفته می‌باشد. برای اعمال فضاهای نام به یکی از دو روش زیر می‌توان عمل کرد:

XName.Get("{mynamespace}root");
//or
XName.Get("root", "mynamespace");

نظرات مطالب
استفاده از Kendo UI templates
از Url.Action باید برای تولید Url استفاده کنید.
قالب پویا بر اساس اطلاعات یک ردیف
#= productDetails(data) #
با این متد
<script>
function productDetails(product) {
    var action = '@Url.Action("ProductDetails", "Product")';

    var html = kendo.format("<a href='{0}/{1}'>Show Product Details</a>",
        action,
        product.ProductID
    );

    return html;
}
</script>
مثال‌های بیشتر در اینجا
مطالب
واکشی اطلاعات به صورت chunk chunk (تکه تکه) و نمایش در ListView
یکی از مسائلی که در هنگام کار با کنترلهای داده‌ای نظیر ListView , GridView و .. با آن روبرو هستیم مسئله صفحه بندی می‌باشد و در بسیاری از موارد، کل اطلاعات در هر درخواست، بارگذاری میشود. در حالیکه روش بهینه به این صورت است که با توجه به PageSize و Index رکورد، می‌توان تعداد رکورد مورد نظر در همان صفحه را بارگذاری کرد، نه کل رکوردها را.
در این مثال که از Ef Code First و الگوی Unit Of Work استفاده کرده ام ، قصد نمایش اطلاعات در یک ListView و صفحه بندی آن را بصورت chunk chunk دارم.
برای آشنایی بیشتر با الگوی Unit Of Work  می‌توانید به مقاله UOW در همین سایت مراجعه کنید.
   
ابتدا یک کنترل ListView روی صفحه ایجاد می‌کنیم. برای آشنایی بیشتر با این کنترل و بررسی قابلیتهای آن میتوان از این مقاله معرفی کنترل‌های ListView و DataPager استفاده کنید.

سپس با توجه به الگوی Unit Of Work از یک مدل ساده استفاده می‌کنیم. همچنین برای بارگذاری اطلاعات به صورت صفحه به صفحه، نیاز به داشتن Index رکورد و PageSize، جهت محاسبه تعداد رکورد مورد نیاز داریم.

public class User
    {       
        public Int64 UserId { get; set; }       
        public String UserName { get; set; }
     }        
 public interface IUserService
    {        
        int GetCustomerCount();
        List<User> GetCustomers(int StartIndex, int PageSize);
    }
public class ImplUserService : IUserService
    {
        IUnitOfWork _uow;
        IDbSet<User> _user;

        public ImplUserService(IUnitOfWork uow)
        {
            _uow = uow;
            _user = uow.Set<User>();
        }

        public int GetCustomerCount()
        {
            int totalCount = _user.ToList().Count;             
            return totalCount;
        }

        public List<User> GetCustomers(int StartIndex, int PageSize)
        {
            return _user.OrderBy(i => i.UserId).Skip(StartIndex).Take(PageSize).ToList();
        }
  }
در کدهای بالا متد GetCustomerCount تعداد کل رکوردهایی که باید واکشی شوند را مشخص می‌کند. همچنین می‌توان این تعداد را در cache یا viewState ذخیره کرد تا در دفعات بعدی در صورت خالی نبودن مقدار Cacheبا viewState ، نیاز به محاسبه مجدد count نداشته باشیم.

متد GetCustomer که کار اصلی را انجام میدهد از دو پارامتر استفاده می‌کند: StartIndex نقطه شروع و PageSize تعداد رکورد مورد نظر. در اینجا از دستورات Linq استفاده شده و دستور Skip مشخص میکند از کدام شماره رکورد به بعد شروع به واکشی نماید و دستور Take مشخص می‌کند که چه تعداد رکورد را واکشی نماید.

حالا به سراغ کدهای HTML می‌رویم. در آنجا علاوه بر ListView نیاز به DataPager جهت صفحه بندی و Object DataSource جهت کنترل بارگذاری اطلاعات به صورت chunk chunk داریم.
<asp:ListView ID="ListView1" runat="server" DataSourceID="ObjectDataSource1">
            <ItemTemplate>
                <tr style="background-color: #DCDCDC; color: #000000;">
                    <td>
                        <asp:Label ID="UserIdLabel" runat="server" Text='<%# Eval("UserId") %>' />
                    </td>
                    <td>
                        <asp:Label ID="UserNameLabel" runat="server" Text='<%# Eval("UserName") %>' />
                    </td>
                </tr>
            </ItemTemplate>
            
            
            <LayoutTemplate>
                <table runat="server">
                    <tr runat="server">
                        <td runat="server">
                            <table id="itemPlaceholderContainer" runat="server" border="1" style="background-color: #FFFFFF;
                                border-collapse: collapse; border-color: #999999; border-style: none; border-width: 1px;">
                                <tr runat="server" style="background-color: #DCDCDC; color: #000000;">
                                    <th runat="server">
                                        UserId
                                    </th>
                                    <th runat="server">
                                        UserName
                                    </th>
                                </tr>
                                <tr id="itemPlaceholder" runat="server">
                                </tr>
                            </table>
                        </td>
                    </tr>
                    <tr runat="server">
                        <td runat="server" style="text-align: center; background-color: #CCCCCC;
                            color: #000000;">
                            <asp:DataPager ID="DataPager1" runat="server" PageSize="2">
                                <Fields>
                                    <asp:NextPreviousPagerField ButtonType="Button" ShowFirstPageButton="True" ShowNextPageButton="False"
                                        ShowPreviousPageButton="False" />
                                    <asp:NumericPagerField />
                                    <asp:NextPreviousPagerField ButtonType="Button" ShowLastPageButton="True" ShowNextPageButton="False"
                                        ShowPreviousPageButton="False" />
                                </Fields>
                            </asp:DataPager>
                        </td>
                    </tr>
                </table>
            </LayoutTemplate>                        
        </asp:ListView>
همانظور که مشاهده میکنید در DataPager ، مقدار PageSize مشخص شده است.اما Object DataSource
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" EnablePaging="True" SelectCountMethod="GetCustomerCount"
            SelectMethod="GetCustomers" TypeName="UserService.ImplUserService" EnableViewState="False"
            MaximumRowsParameterName="PageSize" StartRowIndexParameterName="StartIndex">
که فکر می‌کنم با توجه به متدهای تعریف شده در بالا ، تعریف Object DataSource کاملاٌ گویا میباشد.

نکته مهم:
اگر الان برنامه را اجرا کنید با خطای No parameterless constructor defined for this object ر وبرو خواهید شد که جهت حل این مشکل از کد زیر استفاده میکنیم.
protected void ObjectDataSource1_ObjectCreating(object sender, ObjectDataSourceEventArgs e)
        {            
            e.ObjectInstance = ObjectFactory.GetInstance<IUserService>();            
        }
در واقع نیاز است تا یک وهله از کلاس مورد نظر را به Object DataSource معرفی کنیم.
حال با اجرای برنامه و Trace آن متوجه خواهید شد که با کلیک بر روی شماره صفحه، تنها به تعداد رکوردهای همان صفحه، واکشی خواهیم داشت.

با تشکر از راهنمایی‌های آقای نصیری، امیدوارم این مقاله برای دوستان مفید باشه. منتظر نظرات دوستان هستم و اینکه چه جوری بتونیم اینکار رو با jquery ajax و به صورت سبکتر انجام بدیم.

مطالب
قالبی خودکار برای تهیه‌ی بسته‌های نیوگت
روش‌های زیادی برای تهیه‌ی یک بسته‌ی نیوگت وجود دارند، مانند استفاده از برنامه‌ی NuGet Package Explorer و یا تهیه‌ی یک فایل nuspec و تغییر مداوم جزئیات آن، به ازای هر نگارش جدید پروژه. در ادامه قصد داریم روش خودکار سازی این تغییرات را بررسی کنیم.


الف) تهیه فایل nuspec
NuGet قابلیت پذیرش متغیرهای خود تکمیل شونده‌ای را نیز دارد. فایل nuspec یا جزئیات بسته‌ی تولیدی نیوگت، در این حالت یک چنین شکلی را پیدا می‌کند:
<?xml version="1.0"?>
<package >
 <metadata>
  <id>$id$</id>
  <version>$version$</version>
  <title>$title$</title>
  <authors>$author$</authors>
  <owners>$author$</owners>
  <licenseUrl>https://site.com/prj/LICENSE</licenseUrl>
  <projectUrl>https://site.com/prj</projectUrl>
  <requireLicenseAcceptance>false</requireLicenseAcceptance>
  <description>$description$</description>
  <copyright>Copyright 2015 My Name</copyright>
 </metadata>
</package>
برای مثال اگر پروژه‌ی ما TestNuget نام دارد، فایلی به نام TestNuget.nuspec را با محتویات فوق برای آن تهیه خواهیم کرد. همانطور که مشاهده می‌کنید، در این فایل ویژه، هیچکدام از اطلاعات شماره نگارش پروژه، نام نویسنده و غیره، از پیش تعیین نشده‌اند. این اطلاعات، از فایل AssemblyInfo.cs پروژه، به صورت خودکار دریافت خواهند شد و نکته‌ی مهم آن، قرار گرفتن این فایل nuspec در پوشه‌ی اصلی پروژه است. از این جهت که برای کامپایل آن و تبدیل به یک بسته‌ی نیوگت، فایل nuget.exe را بر روی فایل پروژه‌ی اصلی برنامه اجرا خواهیم کرد و نه بر روی این فایل nuspec.
بنابراین تکمیل اطلاعات فایل AssemblyInfo.cs را فراموش نکنید. برای مثال اطلاعات AssemblyCompany آن، در قسمت authors فایل فوق جایگزین می‌شود.


ب) تهیه فایل NuGet.exe
فایل NuGet.exe را جهت کامپایل فایل فرضی TestNuget.nuspec نیاز داریم. می‌توان آن‌را از سایت کدپلکس تهیه کرد و یا تنها کافی است بر روی Solution موجود در VS.NET کلیک راست کرده و گزینه‌ی Enable NuGet Package Restrore را انتخاب کنیم. با اینکار به صورت خودکار پوشه‌ی ویژه‌ای به نام .nuget به همراه فایل NuGet.exe ایجاد می‌شود.


ج) کامپایل فایل nuspec
در همان پوشه‌ی جدید .nuget، یک فایل bat را با محتوای ذیل تهیه کنید:
 "%~dp0NuGet.exe" pack "..\TestNuGet\TestNuGet.csproj" -Prop Configuration=Release
copy "%~dp0*.nupkg" "%localappdata%\NuGet\Cache"
pause
در این مثال، مسیر TestNuGet\TestNuGet.csproj به محل قرارگیری فایل پروژه‌ی برنامه اشاره می‌کند. در اینجا فایل nuget.exe را بر روی فایل csproj برنامه اجرا خواهیم کرد. با توجه به اینکه قرار است یک بسته‌ی عمومی منتشر شود، بهتر است تنظیمات تولید بسته‌ی نیوگت را بر روی حالت release قرار داد که در این دستور، قید شده‌است.
در ادامه برای اینکه امکان آزمایش محلی این بسته را نیز داشته باشیم، فایل بسته‌ی تولیدی، به کش محلی نیوگت، در سیستم جاری کپی می‌شود.

نکته‌ی جالب این روش، تهیه‌ی قسمت dependencies پروژه، به صورت خودکار است:
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
  <metadata>
    <id>TestNuget</id>
    <version>1.0.0.0</version>
    <title>TestNuget</title>
    <authors>Vahid N.</authors>
    <owners>Vahid N.</owners>
    <licenseUrl>https://site.com/prj/LICENSE</licenseUrl>
    <projectUrl>https://site.com/prj</projectUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>This is a test.</description>
    <copyright>Copyright 2015 My Name</copyright>
    <dependencies>
      <dependency id="EntityFramework" version="6.1.2" />
    </dependencies>
  </metadata>
</package>
اطلاعاتی را که در اینجا مشاهده می‌کنید، حاصل کامپایل فایل nuspec معرفی شده‌ی در ابتدای بحث است (با اجرای فایل bat تهیه شده) که یک کپی از آن در فایل TestNuget.1.0.0.0.nupkg نهایی نیز قرار می‌گیرد. به این ترتیب دیگر نیازی نیست تا این قسمت را به صورت دستی معرفی و هر بار با به روز رسانی وابستگی‌های پروژه، شماره نگارش‌های آن‌ها را نیز به روز کرد. اطلاعات version به صورت خودکار از پروژه‌ی جاری استخراج می‌شوند.


د) آزمایش محلی بسته‌ی جدید
اکنون که فایل TestNuget.1.0.0.0.nupkg تولیدی را در آدرس localappdata%\NuGet\Cache% نیز کپی کرده‌ایم، به منوی Tools/Options مراجعه و در قسمت NuGet Package Manager آن، به قسمت Package sources، این آدرس کش محلی را نیز معرفی کنید:


به این ترتیب، بدون ارسال یک بسته به سایت اصلی نیوگت، می‌توان بسته را از کش محلی نیوگت نصب و آزمایش کرد:



فایل‌های ذکر شده در مطلب فوق را از اینجا می‌توانید دریافت کنید:
TestNuget.zip
 
مطالب
خواندنی‌های 21 فروردین

Velocity راه حل جامع caching مایکروسافت برای ASP.Net است که جزئی از دات نت فریم ورک 4 خواهد بود.


پروژه سورس بازی است که از بسیاری از ماژول‌های جدید دات نت فریم ورک استفاده می‌کند و نکته‌ی جالب نگارش جدید آن مهاجرت از MS Ajax به jQuery Ajax است (قسمت اجکس آن کلا از صفر بر اساس jQuery بازنویسی شده است).

  • چک لیستی که پیش از برپایی یک وب سایت باید بررسی شود.
البته این چک لیست عمومی است و صرفنظر از تکنولوژی بکار گرفته شده در مورد تمامی سایت‌ها صادق است.

ExtJs هم یک دیگر از فریم ورک‌های جاوا اسکریپتی است که با jQuery قابل قیاس است.

  • دمویی در مورد ویندوز Azure و سرویس‌های مبتنی بر آن