نظرات مطالب
شروع به کار با AngularJS 2.0 و TypeScript - قسمت هشتم - دریافت اطلاعات از سرور
- سمت سرور آن مهم نیست (اگر آدرس آن‌را که مستقیما باز می‌کنید، خروجی JSON را مشاهده می‌کنید).
- هر زمانیکه خطای syntax error را دریافت کردید یعنی تنظیمات ابتدایی AngularJS 2.0 شما اشتباه و یا ناقص است.
- این مطالب به روز شده‌اند. نیاز هست توضیحات ذیل هر مطلب را جهت به روز رسانی هر قسمت دنبال کنید.
- و یا ... تمام این توضیحات به صورت یکجا به پروژه‌ی « MVC5Angular2 » اعمال شده‌اند. نیاز است فایل به فایل و سطر به سطر کدهای خود را با این پروژه تطبیق دهید.
نظرات مطالب
شروع به کار با AngularJS 2.0 و TypeScript - قسمت نهم - مسیریابی
چند نکته‌ی تکمیلی
- مسیریابی در نگارش نهایی AngularJS 2.0 تغییرات کلی خواهد داشت. به همین جهت نام ماژول آن‌را به منسوخ شده تغییر داده‌اند (در نگارش RC):
 import { ROUTER_PROVIDERS, RouteConfig, ROUTER_DIRECTIVES } from '@angular/router-deprecated';
- با تغییرات نگارش RC، دیگر نیازی به ذکر router.dev.js در فایل index.html نیست. این مدخل به صورت خودکار توسط systemjs.config.js اضافه می‌شود:
 <script src="~/systemjs.config.js"></script>
نظرات مطالب
AngularJS #2
خود angularjs دارای یک سری api قدرتمند برای اعتبار سنجی هستند. البته انتظار helper‌های شسته رفته asp.net mvc را نداشته باشید که بر اساس model  بتواند اعتبار سنجی سمت کلاینت کند.
باید برایش خودتان دستی کد بنویسید. البته فکر نکنم تهیه‌ی helper برای angular که بر اساس model، کدهای متناظر اعتبار سنجی را تولید کند کار مشکلی باشد.
پاسخ به بازخورد‌های پروژه‌ها
چند متد الحاقی SEO
سلام؛ در مورد seo سایت 
زمانی که سایتی داریم شبیه همین سایت هر مقاله ای که ثبت میشود اطلاعات از database شده و در view ای به نام post نمایش داده میشود . حالا تکلیف Title صفحه و metatag‌ها چی میشود .keyword-description 
مطالب
Markup Extensions در XAML
Markup Extension‌ها برای مواردی استفاده می‌شوند که قرار است مقداری غیر از یک مقدار ثابت و یک نوع قابل شناسایی در XAML برای یک value تنظیم شود. تمام مواردی در XAML که درون {} قرا می‌گیرند همان Markup Extension‌ها هستند. مانند Binding و یا StaticResoiurces.
علاوه بر Markup Extension‌های از پیش تعریف شده در XAML، می‌توان Markup Extension‌های شخصی را نیز تولید کرد. در واقع به زبان ساده‌تر Markup Extension برای تولید ساده‌ی داده‌های پیچیده در XAML استفاده می‌شوند.

لازم به ذکر است کهMarkup Extension ‌ها می‌توانند به دو صورت Attribute Usage ،درون  {} :
 "{Binding path=something,Mode=TwoWay}”
و یا Property Element Usage (همانند سایر Element هایWPF) درون <> استفاده شوند:
 <Binding Path="Something" Mode="TwoWay"></Binding>
برای تعریف یک Markup Extension، یک کلاس ایجاد می‌کنیم که از Markup Extensions ارث بری می‌کند. این کلاس یک Abstract Method به نام  ProvideValue دارد که باید پیاده سازی  شود. این متد مقدار خصوصیتی که Markup Extensions را فراخوانی کرده به صورت یک Object بر می‌گرداند که یکبار در زمان Load برای خصوصیت مربوطه‌اش تنظیم می‌شود.
 public abstract Object ProvideValue(IServiceProvider serviceProvider)
همانطورکه ملاحظه می‌کنید ProvideValue یک پارامتر IServiceProvider دارد که ازطریق آن می‌توان به IProvideValueTarget دسترسی داشت. ازاین Interface برای گرفتن اطلاعات کنترل(TargetObject) و خصوصیتی (TargetProperty) که فراخوانی را انجام داده در صورت لزوم استفاده می‌شود.
var target = serviceProviderGetService(typeof(IProvideValueTarget))as IProvideValueTarget;
var host = targetTargetObject as FrameworkElement;
Markup Extension‌ها می‌توانند پارامتر‌های ورودی داشته باشند:
public class ValueExtension : MarkupExtension
{
  public ValueExtension () { }
  public ValueExtension (object value1)
  {
    Value1 = value1;
  }
   public object Value1 { get; set; }
   public override object ProvideValue(IServiceProvider serviceProvider)
   {
     return Value1;
   }
}
و برای استفاده در فایل Xaml:
 <TextBox  Text="{app:ValueExtension test}" ></TextBox>
و یا می‌توان خصوصیت هایی ایجاد کرد و  از آنها برای ارسال مقادیر به آن استفاده کرد:
  <TextBox  Text="{app:ValueExtension Value1=test}" ></TextBox>
تا اینجا موارد کلی برای تعریف و استفاده از Markup Extensions گفته شد. در ادامه یک مثال کاربردی می‌آوریم. برای مثال در نظر بگیرید که نیاز دارید DataType مربوط به یک DataTemplate را برابر یک کلاس Generic قرار بدهید:
public class EntityBase
{
   public int Id{get;set}
}

public class MyGenericClass<TType> where TType : EntityBase
{
   public int Id{get;set}
   public string Test{  get;set; }

In XAML:

<DataTemplate DataType="{app:GenericType ؟}">
برای انجام این کار یک Markup Extensions به صورت زیر ایجاد می‌کنیم که Type را به عنوان ورودی گرفته و یک نمونه از کلاس Generic ایجاد می‌کند:
public class GenericType : MarkupExtension
{
  private readonly Type _of;
  public GenericType(Type of)
  {
     _of = of;
  }
  public override object ProvideValue(IServiceProvider serviceProvider)
  {
      return typeof(MyGenericClass<>)MakeGenericType(_of);
 }
}
و برای استفاده از آن یک نمونه از MarkupExtension ایجاد شده ایجاد کرده و نوع Generic را برای آن ارسال می‌کنیم:
 <DataTemplate DataType="{app:GenericType app:EntityBase}">
این یک مثال ساده از استفاده از Markup Extensions است. هنگام کار با WPF می‌توان استفاده‌های زیادی از این مفهوم داشت، برای مثال زمانی که نیاز است ItemsSource یک  Combobox  از Description‌های یک Enum پر شود می‌توان به راحتی با نوشتن یک Markup Extensions ساده این عمل و کارهای مشابه زیادی را انجام داد.  
نظرات مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 18 - کار با ASP.NET Web API
ارتقاء به ASP.NET Core 7x

تغییر غیرسازگاری با نگارش‌های قبلی، در ASP.NET Core 7x رخ خواهد که در آن ویژگی [FromServices] که در مطلب جاری بحث شد، پیش‌فرض شده‌است؛ یعنی حتی اگر آن‌را ذکر هم نکردید، مهم نیست و به صورت پیش‌فرض در بین سرویس‌های ثبت شده نیز به دنبال پارامتر اکشن متد مدنظر شما می‌گردد:
Services.AddScoped<SomeCustomType>();

[Route("[controller]")]
[ApiController]
public class MyController : ControllerBase
{
    // Binding from the services
    [HttpPost]
    public ActionResult Post(SomeCustomType service) => Ok();
}
در این مثال، نوع SomeCustomType به صورت یک سرویس، در ابتدای برنامه ثبت شده‌است و همانطور که مشاهده می‌کنید، بدون نیاز به ذکر صریح ویژگی [FromServices]، در اکشن متد Post، مورد استفاده قرار گرفته‌است.
اگر علاقمند به استفاده‌ی از این حالت پیش‌فرض نیستند، روش غیرفعال کردن آن به صورت زیر است:
services.Configure<ApiBehaviorOptions>(options =>
{
     options.DisableImplicitFromServicesParameters = true;
});
مطالب
ساخت یک مثال Todo با MobX و React

پیشنیاز این مطلب مطالعه قسمت MobX می‌باشد. در این مثال قصد داریم  یک برنامه‌ی Todo را با استفاده از MobX و React ایجاد کنیم.


ایجاد ساختار ابتدایی پروژه

برای ساخت پروژه، به خط فرمان مراجعه کرده و با دستور زیر، یک پروژه‌ی react از نوع typescript را ایجاد می‌کنیم. 

npx create-react-app todo-mobx --template typescript 
cd todo-mobx


برای توسعه‌ی این مثال، از محیط توسعه‌ی VSCode استفاده می‌کنیم. اگر VSCode بر روی سیستم شما نصب باشد، در همان مسیری که خط فرمان باز است، دستور زیر را اجرا کنید؛ پروژه‌ی شما در VSCode باز می‌شود:

code


سپس در محیط VSCode، دکمه‌های ctrl+` را فشرده (ctrl+back-tick) و دستورات زیر را در ترمینال ظاهر شده وارد کنید:

npm install --save-dev typescript @types/node @types/react @types/react-dom @types/jest
npm install  mobx mobx-react-lite --save


در ادامه برای استایل بندی بهتر برنامه از کتابخانه‌های bootstrap و  font-awesome استفاده می‌کنیم: 

npm install bootstrap --save
npm install font-awesome --save

سپس فایل index.tsx را باز کرده و دو خط زیر را به آن اضافه می‌کنیم: 

import "bootstrap/dist/css/bootstrap.css";
import "font-awesome/css/font-awesome.css";


کتابخانه‌ی MobX، از تزئین کننده‌ها یا decorators استفاده می‌کند. بنابراین نیاز است به tsconfig پروژه مراجعه کرده و خط زیر را به آن اضافه کنیم:  

"compilerOptions": {
   .... ,
   "experimentalDecorators": true
}


ایجاد مخازن حالت MobX

در ادامه نیاز است store‌های MobX را ایجاد کنیم و بعد آن‌ها را به react اتصال دهیم. بدین منظور یک پوشه‌ی جدید را در مسیر src، به نام stores ایجاد می‌کنیم و سپس فایل جدیدی را به نام todo-item.ts در آن با محتوای زیر ایجاد می‌کنیم: 

import { observable, action } from "mobx";

export default class TodoItem {
    id = Date.now();

    @observable text: string = '';
    @observable isDone: boolean = false;

    constructor(text: string) {
        this.text = text;
    }

    @action
    toggleIsDone = () => {
        this.isDone = !this.isDone
    }

    @action
    updateText = (text: string) => {
        this.text = text;
    }
}


در همان مسیر stores، فایل دیگری را نیز به نام todo-list.ts، با محتوای زیر ایجاد می‌کنیم:

import { observable, computed, action } from "mobx";

import TodoItem from "./todo-item";

export class TodoList {
    @observable.shallow list: TodoItem[] = [];

    constructor(todos: string[]) {
        todos.forEach(this.addTodo);
    }

    @action
    addTodo = (text: string) => {
        this.list.push(new TodoItem(text));
    }

    @action
    removeTodo = (todo: TodoItem) => {
        this.list.splice(this.list.indexOf(todo), 1);
    };

    @computed
    get finishedTodos(): TodoItem[] {
        return this.list.filter(todo => todo.isDone);
    }

    @computed
    get openTodos(): TodoItem[] {
        return this.list.filter(todo => !todo.isDone);
    }
}

توضیحات:

مفهوم observable@: کل شیء state را به صورت یک شیء قابل ردیابی JavaScript ای ارائه می‌کند.

مفهوم computed@: این نوع خواص، مقدار خود را زمانیکه observable‌های وابسته‌ی به آن‌ها تغییر کنند، به روز رسانی می‌کنند.

مفهوم action@: جهت به روز رسانی state و سپس نمایش تغییرات یا نمایش نمونه‌ی دیگری در DOM می‌باشند.



برپایی Context
در این مثال از شیء Provider خود MobX استفاده نمی‌کنیم؛ بلکه از React Context استفاده می‌کنیم. به همین جهت در مسیر src، یک پوشه‌ی جدید دیگر را به نام Providers ایجاد می‌کنیم. سپس فایلی را به نام store-provider.ts ایجاد کرده و کدهای زیر را به آن اضافه می‌کنیم: 
import { createContext, useContext } from "react";
import { TodoList } from "../stores/todo-list";

export const StoreContext = createContext<TodoList>({} as TodoList);
export const StoreProvider = StoreContext.Provider;

export const useStore = (): TodoList => useContext(StoreContext);
توضیحات:
- در اینجا StoreContext را ایجاد کرده و سپس به آن یک مقدار پیش فرض از نوع یک object خالی را ارسال کرده‌ایم.
- سپس بر اساس آن، شیء StoreProvider را که از نوع ReactConxtext می‌باشد، ایجاد کردیم. 
- متد useStore که به صورت export و نوعی از useContext می‌باشد، برای دسترسی ساده‌تر به Context معرفی شده‌است که در ادامه کاربرد آن‌را خواهید دید.
- برای اعمال StoreProvider در شروع کننده‌ی برنامه React، به فایل index.tsx مراجعه کرده و آن‌را به صورت زیر ویرایش می‌کنیم: 
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import "bootstrap/dist/css/bootstrap.css";
import "font-awesome/css/font-awesome.css";
import { TodoList } from './stores/todo-list';
import { StoreProvider } from './providers/store-provider';


const todoList = new TodoList([
    'Read Book',
    'Do exercise',
    'Watch Walking dead series'
]);

ReactDOM.render(
    <StoreProvider value={todoList}>
        <App />
    </StoreProvider>
    , document.getElementById('root'));

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
توضیحات:  StoreProvider ای را که در فایل store-provider.ts ایجاد کردیم، در اینجا به شروع کننده‌ی React معرفی می‌کنیم و سه مقدار پیش فرض را نیز به آن اعمال می‌کنیم.

افزودن کامپوننت‌های برنامه
برای نمایش لیست Todo‌ها و عملیات حذف، اضافه و ویرایش، نیاز به سه کامپوننت تابعی را داریم: 

اضافه کردن کامپوننت TodoNew
در مسیر src، یک پوشه‌ی جدید را به نام components ایجاد می‌کنیم. سپس فایلی را در آن به نام TodoNew.tsx ایجاد کرده و کدهای زیر را به آن اضافه می‌کنیم: 
import React, { useState } from 'react';
import { useStore } from '../providers/store-provider';

export const TodoNew = () => {
    const [newTodo, setTodo] = useState('');
    const todoList = useStore();

    const addTodo = () => {
        todoList.addTodo(newTodo);
        setTodo('');
    };

    return (

        <div className="input-group mb-3">
            <input type="text" className="form-control" placeholder="Add To do" value={newTodo} onChange={(e) => setTodo(e.target.value)} />
            <div className="input-group-append">
                <button className="btn btn-success" type="submit" onClick={addTodo}>Add Todo</button>
            </div>
        </div>
    )
};
توضیحات: 
- useStore ای را که در مرحله‌ی قبل ایجاد کردیم، در اینجا برای دسترسی به state‌های MobX استفاده می‌کنیم.
- در input و رویداد onChange آن، مقدار ورودی کاربر را به متد newTodo اعمال می‌کنیم و بعد از اینکه کاربر دکمه‌ی Add Todo را زد، مقدار newTodo را به تابع addTodo که در useStore می‌باشد، اعمال می‌کنیم.

افزودن کامپوننت نمایش لیست کارها: TodoList
در مسیر src و پوشه‌ی components آن، فایل جدیدی را به نام TodoList.tsx ایجاد کرده و کدهای زیر را به آن اضافه می‌کنیم: 
import React from 'react';

import { TodoItem } from "./TodoItem";
import { useObserver } from "mobx-react-lite";
import { useStore } from '../providers/store-provider';

export const TodoList = () => {
    const todoList = useStore();

    return useObserver(() => (
        <div>
            <h1>Open Todos</h1>
            <table className="table">
                <thead className="thead-dark">
                    <tr>
                        <th>Name</th>
                        <th className="text-left">Do It?</th>
                        <th>Actions</th>
                    </tr>
                </thead>
                <tbody>
                    {
                        todoList.openTodos.map(todo =>
                            <tr key={`${todo.id}-${todo.text}`}>
                                <TodoItem todo={todo} />
                            </tr>)
                    }

                </tbody>
            </table>

            <h1>Finished Todos</h1>
            <table className="table">
                <thead className="thead-light">
                    <tr>
                        <th>Name</th>
                        <th className="text-left">Do It?</th>
                        <th>Actions</th>
                    </tr>
                </thead>
                <tbody>
                    {
                        todoList.finishedTodos.map(todo =>
                            <tr key={`${todo.id}-${todo.text}`}>
                                <TodoItem todo={todo} />
                            </tr>)
                    }

                </tbody>
            </table>
        </div>
    ));
};
توضیحات:
- useStore را به ثابت todoList انتساب می‌دهیم.
- سپس برای نمایش Todo ‌ها، یک جدول را طراحی می‌کنیم و همچنین برای نمایش کارهای تکمیل شده (Finish Todo) جدول دیگری را ایجاد می‌کنیم.
- در کلاس TodoList، که پیشتر آن‌را ایجاد کردیم، از دو خاصیت openTodos و finishedTodos از نوع get که با Decorator از نوع computed@ هستند، برای نمایش Open Todos و Finished Todos استفاده می‌کنیم. خروجی این خواص، لیستی از نوع TodoItem می‌باشند که با کمک متد map، به فیلد‌های TodoItem آن‌ها دسترسی پیدا می‌کنیم.

برای منظم کردن کدها، کامپوننت دیگری را در مسیر src/components به نام TodoItem.tsx ایجاد کرده و کدهای زیر را به آن اضافه می‌کنیم: 
import React, { useState } from 'react';
import TodoItemClass from "../stores/todo-item";


import { useStore } from '../providers/store-provider';

interface Props {
    todo: TodoItemClass;
}

export const TodoItem = ({ todo }: Props) => {
    const todoList = useStore();
    const [newText, setText] = useState('');
    const [isEditing, setEdit] = useState(false);

    const saveText = () => {
        todo.updateText(newText);
        setEdit(false);
        setText('');
    };

    return (
        <React.Fragment>
            {
                isEditing ?
                    <React.Fragment>
                        <td>
                            <input className="form-control" placeholder={todo.text} type="text" onChange={(e) => setText(e.target.value)} />
                        </td>
                        <td></td>
                        <td>
                            <button className="btn btn-xs btn-success " onClick={saveText}>Save</button>
                        </td>
                    </React.Fragment>
                    :
                    <React.Fragment>
                        <td>
                            {todo.text}
                        </td>

                        <td className="text-left">
                            <input className="form-check-input" type="checkbox" onChange={todo.toggleIsDone} defaultChecked={todo.isDone}></input>
                        </td>
                        <td>
                            <button className="btn btn-xs btn-warning " onClick={() => setEdit(true)}>
                                <i className="fa fa-edit"></i>
                            </button>
                            <button className="btn btn-xs btn-danger ml-2" onClick={() => todoList.removeTodo(todo)}>
                                <i className="fa fa-remove"></i>
                            </button>
                        </td>
                    </React.Fragment>
            }

        </React.Fragment>

    )
};
توضیحات:
- در کامپوننت قبلی TodoList.tsx، متدهای TodoItem را به کامپوننت TodoItem.tsx پاس داده و آن را در دو حالت ویرایش و نمایش، نشان می‌دهیم.
- در جدول، امکان ویرایش، حذف و ثبت رکوردها را قرار داده‌ایم. برای ویرایش، مقدار input وارد شده را به متد (todo.updateText(newText پاس می‌دهیم و برای حذف، (todoList.removeTodo(todo را فراخوانی می‌کنیم.
 
کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید  Github
مطالب
ASP.NET MVC #10

آشنایی با روش‌های مختلف ارسال اطلاعات یک درخواست به کنترلر

تا اینجا با روش‌های مختلف ارسال اطلاعات از یک کنترلر به View متناظر آن آشنا شدیم. اما حالت عکس آن چطور؟ مثلا در ASP.NET Web forms، دوبار بر روی یک دکمه کلیک می‌کردیم و در روال رویدادگردان کلیک آن، همانند برنامه‌های ویندوزی، دسترسی به اطلاعات اشیاء قرار گرفته بر روی فرم را داشتیم. در ASP.NET MVC که کلا مفهوم Events را حذف کرده و وب را همانگونه که هست ارائه می‌دهد و به علاوه کنترلرهای آن، ارجاع مستقیمی را به هیچکدام از اشیاء بصری در خود ندارند (برای مثال کنترلر و متدی در آن نمی‌دانند که الان بر روی View آن، یک گرید قرار دارد یا یک دکمه یا اصلا هیچی)، چگونه می‌توان اطلاعاتی را از کاربر دریافت کرد؟
در اینجا حداقل سه روش برای دریافت اطلاعات از کاربر وجود دارد:
الف) استفاده از اشیاء Context مانند HttpContext، Request، RouteData و غیره
ب) به کمک پارامترهای اکشن متدها
ج) با استفاده از ویژگی جدیدی به نام Data Model Binding

یک مثال کاربردی
قصد داریم یک صفحه لاگین ساده را طراحی کنیم تا بتوانیم هر سه حالت ذکر شده فوق را در عمل بررسی نمائیم. بحث HTML Helpers استاندارد ASP.NET MVC را هم که در قسمت قبل شروع کردیم، لابلای توضیحات قسمت جاری و قسمت‌های بعدی با مثال‌های کاربردی دنبال خواهند شد.
بنابراین یک پروژه جدید خالی ASP.NET MVC را شروع کرده و مدلی را به نام Account با محتوای زیر به پوشه Models برنامه اضافه کنید:

namespace MvcApplication6.Models
{
public class Account
{
public string Name { get; set; }
public string Password { get; set; }
}
}

یک کنترلر جدید را هم به نام LoginController به پوشه کنترلرهای برنامه اضافه کنید. بر روی متد Index پیش فرض آن کلیک راست نمائید و یک View خالی را اضافه نمائید.
در ادامه به فایل Global.asax.cs مراجعه کرده و نام کنترلر پیش‌فرض را به Login تغییر دهید تا به محض شروع برنامه در VS.NET، صفحه لاگین ظاهر شود.
کدهای کامل کنترلر لاگین را در ادامه ملاحظه می‌کنید:

using System.Web.Mvc;
using MvcApplication6.Models;

namespace MvcApplication6.Controllers
{
public class LoginController : Controller
{
[HttpGet]
public ActionResult Index()
{
return View(); //Shows the login page
}

[HttpPost]
public ActionResult LoginResult()
{
string name = Request.Form["name"];
string password = Request.Form["password"];

if (name == "Vahid" && password == "123")
ViewBag.Message = "Succeeded";
else
ViewBag.Message = "Failed";

return View("Result");
}

[HttpPost]
[ActionName("LoginResultWithParams")]
public ActionResult LoginResult(string name, string password)
{
if (name == "Vahid" && password == "123")
ViewBag.Message = "Succeeded";
else
ViewBag.Message = "Failed";

return View("Result");
}

[HttpPost]
public ActionResult Login(Account account)
{
if (account.Name == "Vahid" && account.Password == "123")
ViewBag.Message = "Succeeded";
else
ViewBag.Message = "Failed";

return View("Result");
}
}
}

همچنین Viewهای متناظر با این کنترلر هم به شرح زیر هستند:
فایل index.cshtml به نحو زیر تعریف خواهد شد:

@model MvcApplication6.Models.Account
@{
ViewBag.Title = "Index";
}
<h2>
Login</h2>
@using (Html.BeginForm(actionName: "LoginResult", controllerName: "Login"))
{
<fieldset>
<legend>Test LoginResult()</legend>
<p>
Name: @Html.TextBoxFor(m => m.Name)</p>
<p>
Password: @Html.PasswordFor(m => m.Password)</p>
<input type="submit" value="Login" />
</fieldset>
}
@using (Html.BeginForm(actionName: "LoginResultWithParams", controllerName: "Login"))
{
<fieldset>
<legend>Test LoginResult(string name, string password)</legend>
<p>
Name: @Html.TextBoxFor(m => m.Name)</p>
<p>
Password: @Html.PasswordFor(m => m.Password)</p>
<input type="submit" value="Login" />
</fieldset>
}
@using (Html.BeginForm(actionName: "Login", controllerName: "Login"))
{
<fieldset>
<legend>Test Login(Account acc)</legend>
<p>
Name: @Html.TextBoxFor(m => m.Name)</p>
<p>
Password: @Html.PasswordFor(m => m.Password)</p>
<input type="submit" value="Login" />
</fieldset>
}

و فایل result.cshtml هم محتوای زیر را دارد:

@{
ViewBag.Title = "Result";
}
<fieldset>
<legend>Login Result</legend>
<p>
@ViewBag.Message</p>
</fieldset>

توضیحاتی در مورد View لاگین برنامه:
در View صفحه لاگین سه فرم را مشاهده می‌کنید. در برنامه‌های ASP.NET Web forms در هر صفحه، تنها یک فرم را می‌توان تعریف کرد؛ اما در ASP.NET MVC این محدودیت برداشته شده است.
تعریف یک فرم هم با متد کمکی Html.BeginForm انجام می‌شود. در اینجا برای مثال می‌شود یک فرم را به کنترلری خاص و متدی مشخص در آن نگاشت نمائیم.
از عبارت using هم برای درج خودکار تگ بسته شدن فرم، در حین dispose شیء MvcForm کمک گرفته شده است.
برای نمونه خروجی HTML اولین فرم تعریف شده به صورت زیر است:

<form action="/Login/LoginResult" method="post">   
<fieldset>
<legend>Test LoginResult()</legend>
<p>
Name: <input id="Name" name="Name" type="text" value="" /></p>
<p>
Password: <input id="Password" name="Password" type="password" /></p>
<input type="submit" value="Login" />
</fieldset>
</form>

توسط متدهای کمکی Html.TextBoxFor و Html.PasswordFor یک TextBox و یک PasswordBox به صفحه اضافه می‌شوند، اما این For آن‌ها و همچنین lambda expression ایی که بکارگرفته شده برای چیست؟
متدهای کمکی Html.TextBox و Html.Password از نگارش‌های اولیه ASP.NET MVC وجود داشتند. این متدها نام خاصیت‌ها و پارامترهایی را که قرار است به آن‌ها بایند شوند، به صورت رشته می‌پذیرند. اما با توجه به اینکه در اینجا می‌توان یک strongly typed view را تعریف کرد،‌ تیم ASP.NET MVC بهتر دیده است که این رشته‌ها را حذف کرده و از قابلیتی به نام Static reflection استفاده کند (^ و ^).

با این توضیحات، اطلاعات سه فرم تعریف شده در View لاگین برنامه، به سه متد متفاوت قرار گرفته در کنترلری به نام Login ارسال خواهند شد. همچنین با توجه به مشخص بودن نوع model که در ابتدای فایل تعریف شده، خاصیت‌هایی را که قرار است اطلاعات ارسالی به آن‌ها بایند شوند نیز به نحو strongly typed تعریف شده‌اند و تحت نظر کامپایلر خواهند بود.


توضیحاتی در مورد نحوه عملکرد کنترلر لاگین برنامه:

در این کنترلر صرفنظر از محتوای متدهای آن‌ها، دو نکته جدید را می‌توان مشاهده کرد. استفاده از ویژگی‌های HttpPost، HttpGet و ActionName. در اینجا به کمک ویژگی‌های HttpGet و HttpPost در مورد نحوه دسترسی به این متدها، محدودیت قائل شده‌ایم. به این معنا که تنها در حالت Post است که متد LoginResult در دسترس خواهد بود و اگر شخصی نام این متدها را مستقیما در مرورگر وارد کند (یا همان HttpGet پیش فرض که نیازی هم به ذکر صریح آن نیست)، با پیغام «یافت نشد» مواجه می‌گردد.
البته در نگارش‌های اولیه ASP.NET MVC از ویژگی دیگری به نام AcceptVerbs برای مشخص سازی نوع محدودیت فراخوانی یک اکشن متد استفاده می‌شد که هنوز هم معتبر است. برای مثال:

[AcceptVerbs(HttpVerbs.Get)]

یک نکته امنیتی:
همیشه متدهای Delete خود را به HttpPost محدود کنید. به این علت که ممکن است در طی مثلا یک ایمیل، آدرسی به شکل http://localhost/blog/delete/10 برای شما ارسال شود و همچنین سشن کار با قسمت مدیریتی بلاگ شما نیز در همان حال فعال باشد. URL ایی به این شکل، در حالت پیش فرض، محدودیت اجرایی HttpGet را دارد. بنابراین احتمال اجرا شدن آن بالا است. اما زمانیکه متد delete را به HttpPost محدود کردید، دیگر این نوع حملات جواب نخواهند داد و حتما نیاز خواهد بود تا اطلاعاتی به سرور Post شود و نه یک Get ساده (مثلا کلیک بر روی یک لینک معمولی)، کار حذف را انجام دهد.


توسط ActionName می‌توان نام دیگری را صرفنظر از نام متد تعریف شده در کنترلر، به آن متد انتساب داد که توسط فریم ورک در حین پردازش نهایی مورد استفاده قرار خواهد گرفت. برای مثال در اینجا به متد LoginResult دوم، نام LoginResultWithParams را انتساب داده‌ایم که در فرم دوم تعریف شده در View لاگین برنامه مورد استفاده قرار گرفته است.
وجود این ActionName هم در مثال فوق ضروری است. از آنجائیکه دو متد هم نام را معرفی کرده‌ایم و فریم ورک نمی‌داند که کدامیک را باید پردازش کند. در این حالت (بدون وجود ActionName معرفی شده)، برنامه با خطای زیر مواجه می‌گردد:

The current request for action 'LoginResult' on controller type 'LoginController' is ambiguous between the following action methods:
System.Web.Mvc.ActionResult LoginResult() on type MvcApplication6.Controllers.LoginController
System.Web.Mvc.ActionResult LoginResult(System.String, System.String) on type MvcApplication6.Controllers.LoginController

برای اینکه بتوانید نحوه نگاشت فرم‌ها به متدها را بهتر درک کنید، بر روی چهار return View موجود در کنترلر لاگین برنامه، چهار breakpoint را تعریف کنید. سپس برنامه را در حالت دیباگ اجرا نمائید و تک تک فرم‌ها را یکبار با کلیک بر روی دکمه لاگین، به سرور ارسال نمائید.


بررسی سه روش دریافت اطلاعات از کاربر در ASP.NET MVC

الف) استفاده از اشیاء Context

در ویژوال استودیو، در کنترلر لاگین برنامه، بر روی کلمه Controller کلیک راست کرده و گزینه Go to definition را انتخاب کنید. در اینجا بهتر می‌توان به خواصی که در یک کنترلر به آن‌ها دسترسی داریم، نگاهی انداخت:

public HttpContextBase HttpContext { get; }
public HttpRequestBase Request { get; }
public HttpResponseBase Response { get; }
public RouteData RouteData { get; }

در بین این خواص و اشیاء مهیا، Request و RouteData بیشتر مد نظر ما هستند. در مورد RouteData در قسمت ششم این سری، توضیحاتی ارائه شد. اگر مجددا Go to definition مربوط به HttpRequestBase خاصیت Request را بررسی کنیم، موارد ذیل جالب توجه خواهند بود:

public virtual NameValueCollection QueryString { get; } // GET variables
public NameValueCollection Form { get; } // POST variables
public HttpCookieCollection Cookies { get; }
public NameValueCollection Headers { get; }
public string HttpMethod { get; }

توسط خاصیت Form شیء Request می‌توان به مقادیر ارسالی به سرور در یک کنترلر دسترسی یافت که نمونه‌ای از آن‌را در اولین متد LoginResult می‌توانید مشاهده کنید. این روش در ASP.NET Web forms هم کار می‌کند. جهت اطلاع این روش با ASP کلاسیک دهه نود هم سازگار است!
البته این روش آنچنان مرسوم نیست؛ چون NameValueCollection مورد استفاده، ایندکسی عددی یا رشته‌ای را می‌پذیرد که هر دو با پیشرفت‌هایی که در زبان‌های دات نتی صورت گرفته‌اند، دیگر آنچنان مطلوب و روش مرجح به حساب نمی‌آیند. اما ... هنوز هم قابل استفاده است.
به علاوه اگر دقت کرده باشید در اینجا HttpContextBase داریم بجای HttpContext. تمام این کلاس‌های پایه هم به جهت سهولت انجام آزمون‌های واحد در ASP.NET MVC ایجاد شده‌اند. کار کردن مستقیم با HttpContext مشکل بوده و نیاز به شبیه سازی فرآیندهای رخ داده در یک وب سرور را دارد. اما این کلاس‌های پایه جدید، مشکلات یاد شده را به همراه ندارند.


ب) استفاده از پارامترهای اکشن متدها

نکته‌ای در مورد نامگذاری پارامترهای یک اکشن متد به صورت توکار اعمال می‌شود که باید به آن دقت داشت:
اگر نام یک پارامتر، با نام کلید یکی از رکوردهای موجود در مجموعه‌های زیر یکی باشد، آنگاه به صورت خودکار اطلاعات دریافتی به این پارامتر نگاشت خواهد شد (پارامتر هم نام، به صورت خودکار مقدار دهی می‌شود). این مجموعه‌ها شامل موارد زیرهستند:

Request.Form
Request.QueryString
Request.Files
RouteData.Values

برای نمونه در متدی که با نام LoginResultWithParams مشخص شده، چون نام‌های دو پارامتر آن، با نام‌های بکارگرفته شده در Html.TextBoxFor و Html.PasswordFor یکی هستند، با مقادیر ارسالی آن‌ها مقدار دهی شده و سپس در متد قابل استفاده خواهند بود. در پشت صحنه هم از همان رکوردهای موجود در Request.Form (یا سایر موارد ذکر شده)، استفاده می‌شود. در اینجا هر رکورد مثلا مجموعه Request.Form، کلیدی مساوی نام ارسالی به سرور را داشته و مقدار آن هم، مقداری است که کاربر وارد کرده است.
اگر همانندی یافت نشد، آن پارامتر با نال مقدار دهی می‌گردد. بنابراین اگر برای مثال یک پارامتر از نوع int را معرفی کرده باشید و چون نوع int، نال نمی‌پذیرد، یک استثناء بروز خواهد کرد. برای حل این مشکل هم می‌توان از Nullable types استفاده نمود (مثلا بجای int id نوشت int? id تا مشکلی جهت انتساب مقدار نال وجود نداشته باشد).
همچنین باید دقت داشت که این بررسی تطابق‌های بین نام عناصر HTML و نام پارامترهای متدها، case insensitive است و به کوچکی و بزرگی حروف حساس نیست. برای مثال، پارامتر معرفی شده در متد LoginResult مساوی string name است، اما نام خاصیت تعریف شده در کلاس Account مساوی Name بود.


ج) استفاده از ویژگی جدیدی به نام Data Model Binding

در ASP.NET MVC چون می‌توان با یک Strongly typed view کار کرد، خود فریم ورک این قابلیت را دارد که اطلاعات ارسالی یکی فرم را به صورت خودکار به یک وهله از یک شیء نگاشت کند. در اینجا model binder وارد عمل می‌شود، مقادیر ارسالی را استخراج کرده (اطلاعات دریافتی از Form یا کوئری استرینگ‌ها یا اطلاعات مسیریابی و غیره) و به خاصیت‌های یک شیء نگاشت می‌کند. بدیهی است در اینجا این خواص باید عمومی باشند و هم نام عناصر HTML ارسالی به سرور. همچنین model binder پیش فرض ASP.NET MVC را نیز می‌توان کاملا تعویض کرد و محدود به استفاده از model binder توکار آن نیستیم.
وجود این Model binder، کار با ORMها را بسیار لذت بخش می‌کند؛ از آنجائیکه خود فریم ورک ASP.NET MVC می‌تواند عناصر شیءایی را که قرار است به بانک اطلاعاتی اضافه شود، یا در آن به روز شود، به صورت خودکار ایجاد کرده یا به روز رسانی نماید.
نحوه کار با model binder را در متد Login کنترلر فوق می‌توانید مشاهده کنید. بر روی return View آن یک breakpoint قرار دهید. فرم سوم را به سرور ارسال کنید و سپس در VS.NET خواص شیء ساخته شده را در حین دیباگ برنامه، بررسی نمائید.
بنابراین تفاوتی نمی‌کند که از چندین پارامتر استفاده کنید یا اینکه کلا یک شیء را به عنوان پارامتر معرفی نمائید. فریم ورک سعی می‌کند اندکی هوش به خرج داده و مقادیر ارسالی به سرور را به پارامترهای تعریفی، حتی به خواص اشیاء این پارامترهای تعریف شده، نگاشت کند.

در ASP.NET MVC سه نوع Model binder وجود دارند:
1) Model binder پیش فرض که توضیحات آن به همراه مثالی ارائه شد.
2) Form collection model binder که در ادامه توضیحات آن‌را مشاهده خواهید نمود.
3) HTTP posted file base model binder که توضیحات آن به قسمت بعدی موکول می‌شود.

یک نکته:
اولین متد LoginResult کنترلر را به نحو زیر نیز می‌توان بازنویسی کرد:
[HttpPost]
[ActionName("LoginResultWithFormCollection")]
public ActionResult LoginResult(FormCollection collection)
{
string name = collection["name"];
string password = collection["password"];

if (name == "Vahid" && password == "123")
ViewBag.Message = "Succeeded";
else
ViewBag.Message = "Failed";

return View("Result");
}

در اینجا FormCollection به صورت خودکار بر اساس مقادیر ارسالی به سرور توسط فریم ورک تشکیل می‌شود (FormCollection هم یک نوع model binder ساده است) و اساسا یک NameValueCollection می‌باشد.
بدیهی است در این حالت باید نگاشت مقادیر دریافتی، به متغیرهای متناظر با آن‌ها، دستی انجام شود (مانند مثال فوق) یا اینکه می‌توان از متد UpdateModel کلاس Controller هم استفاده کرد:

[HttpPost]
public ActionResult LoginResultUpdateFormCollection(FormCollection collection)
{
var account = new Account();
this.UpdateModel(account, collection.ToValueProvider());

if (account.Name == "Vahid" && account.Password == "123")
ViewBag.Message = "Succeeded";
else
ViewBag.Message = "Failed";

return View("Result");
}

متد توکار UpdateModel، به صورت خودکار اطلاعات FormCollection دریافتی را به شیء مورد نظر، نگاشت می‌کند.
همچنین باید عنوان کرد که متد UpdateModel، در پشت صحنه از اطلاعات Model binder پیش فرض و هر نوع Model binder سفارشی که ایجاد کنیم استفاده می‌کند. به این ترتیب زمانیکه از این متد استفاده می‌کنیم، اصلا نیازی به استفاده از FormCollection نیست و متد بدون آرگومان زیر هم به خوبی کار خواهد کرد:

[HttpPost]
public ActionResult LoginResultUpdateModel()
{
var account = new Account();
this.UpdateModel(account);

if (account.Name == "Vahid" && account.Password == "123")
ViewBag.Message = "Succeeded";
else
ViewBag.Message = "Failed";

return View("Result");
}

استفاده از model binderها همینجا به پایان نمی‌رسد. نکات تکمیلی آن‌ها در قسمت بعدی بررسی خواهند شد.

اشتراک‌ها
ایجاد نمودار با استفاده از AngularJS و Web API

In development world, you may get a requirement from your client, they wants a weekly, quarterly and yearly charts. You always think, how can I make charts with use of angularjs.  So today, in this article, we are going to learn

  • how to create charts in angularjs using webapi
  •  higcharts.js

In this example, our requirement is, we have dropdownlist of student names. if user select any student, it will show selected students marks in the form of charts. 

ایجاد نمودار با استفاده از AngularJS و Web API
مطالب
زیرنویس فارسی ویدئوهای مقدمات AngularJS - قسمت اول
سایت pluralsight یک دوره آموزشی با عنوان AngularJS Fundamentals تهیه کرده است، که به آموزش مقدمات AngularJS و اینکه چگونه می‌توانیم برنامه هایی با قابلیت تست پذیری، SPA و به سبک MVC بنویسیم، می‌پردازد.
فعلاً قسمت اول این مجموعه زیرنویس شده است که از اینجا  قابل دریافت می‌باشد، جهت مشاهده ویدئوها نیز پیشنهاد می‌شود از برنامه KMPlayer استفاده کنید.
لیست ویدئوهای قسمت اول این مجموعه به شرح زیر است :
Course Introduction
Module Introduction
Introduction to Angular
Angular Architecture
Demo: Hello World in Angular
The Angular Event Reg Application
Angular Seed
Summary
6 قسمت دیگر از این مجموعه باقیمانده است، که بعد از آماده شدن به همین ترتیب به صورت یک پست در سایت ارائه خواهد شد. اگر مایل به همکاری بودید در قسمت پروژه‌های سایت می‌توانید اقدام کنید.
برای تهیه زیرنویس‌ها هم از برنامه Subtitle Tools استفاده میکنم، البته ظاهراً خود ویدئوها دارای زیرنویس انگلیسی هستند که رایگان نیستند.