نظرات مطالب
بررسی دقیق‌تر صفحات آبی ویندوز
سلام،
لطفا فایل‌های دامپ حاصل شده(اگر به روشی که گفتم عمل کرده باشید، یک سری فایل باید در فولدر c:\WINDOWS\Minidump تولید شده باشد) را در mediafire.com آپلود کنید تا آن‌ها را بررسی کنم.
پاسخ به بازخورد‌های پروژه‌ها
فضای نام MVC
سلام؛
راستش من مشکلی ندارم.حجمش حدود 30 مگابایت میشود. حالا دوستان راهنمایی کنند که کجا آپلود کنم؟
(همینجا یا جای دیگری)
مطالب
سعی مجدد خودکار درخواست‌های با شکست مواجه شده در برنامه‌های Angular
در دنیای واقعی، تمام درخواست‌های HTTP ارسالی به سمت سرور، با موفقیت به آن نمی‌رسند. ممکن است در یک لحظه سرور در دسترس نباشد. در لحظه‌ای دیگر آنقدر بار آن بالا باشد که نتواند درخواست شما را پردازش کند و یا ممکن است درست در لحظه‌ای که توکن دسترسی به برنامه در حال به روز رسانی است، درخواست دیگری به سمت سرور ارسال شده باشد که حتما برگشت خواهد خورد؛ چون حاوی توکن جدید صادر شده نیست. در تمام این موارد ضرورت تکرار و سعی مجدد درخواست‌های شکست خورده وجود دارد. برای مدیریت این مساله در برنامه‌های Angular می‌توان از امکانات توکار کتابخانه‌ی RxJS به همراه آن کمک گرفت.


سعی مجدد خودکار درخواست‌ها توسط کتابخانه‌ی RxJS

با استفاده از عملگر retry می‌توان به صورت خودکار، درخواست‌های شکست خورده را به تعداد باری که مشخص می‌شود، تکرار کرد:
import { Observable } from "rxjs";
import { catchError, map, retry } from "rxjs/operators";

postEmployeeForm(employee: Employee): Observable<Employee> {
    const headers = new HttpHeaders({ "Content-Type": "application/json" });
    return this.http
      .post(this.baseUrl, employee, { headers: headers })
      .pipe(
        map((response: any) => response["fields"] || {}),
        catchError(this.handleError),
        retry(3)
      );
  }
در اینجا اگر درخواست اول با شکست مواجه شود، اصل آن‌را سه بار دیگر به سمت سرور ارسال می‌کند (البته در صورت بروز و دریافت خطای مجدد).
مشکل این روش در عدم وجود مکثی بین درخواست‌ها است. در اینجا تمام درخواست‌های سعی مجدد، بلافاصله به سمت سرور ارسال می‌شوند. همچنین نمی‌توان مشخص کرد که اگر مثلا خطای timeout وجود داشت، اینکار را تکرار کن و نه برای سایر حالات.


سفارشی سازی سعی مجدد خودکار درخواست‌ها، توسط کتابخانه‌ی RxJS

برای اینکه بتوان کنترل بیشتری را بر روی سعی‌های مجدد انجام شده داشت، می‌توان از عملگر retryWhen بجای retry استفاده کرد:
import { Observable, of, throwError as observableThrowError, throwError } from "rxjs";
import { catchError, delay, map, retryWhen, take } from "rxjs/operators";

postEmployeeForm(employee: Employee): Observable<Employee> {
    const headers = new HttpHeaders({ "Content-Type": "application/json" });
    return this.http
      .post(this.baseUrl, employee, { headers: headers })
      .pipe(
        map((response: any) => response["fields"] || {}),
        retryWhen(errors => errors.pipe(
          delay(1000),
          take(3)
        )),
        catchError(this.handleError)
      );
  }
در اینجا توسط عملگر retryWhen، کار سفارشی سازی سعی‌های مجدد درخواست‌های شکست خورده انجام شده‌است. در این مثال پس از هر درخواست مجدد، 1000ms صبر شده و سپس درخواست دیگری درصورت وجود خطا، به سمت سرور تا حداکثر 3 بار، ارسال می‌شود.

در ادامه اگر بخواهیم صرفا به خطاهای خاصی واکنش نشان دهیم می‌توان به صورت زیر عمل کرد:
import { Observable, of, throwError as observableThrowError, throwError } from "rxjs";
import { catchError, delay, map, mergeMap, retryWhen, take } from "rxjs/operators";

postEmployeeForm(employee: Employee): Observable<Employee> {
    const headers = new HttpHeaders({ "Content-Type": "application/json" });
    return this.http
      .post(this.baseUrl, employee, { headers: headers })
      .pipe(
        map((response: any) => response["fields"] || {}),
        retryWhen(errors => errors.pipe(
          mergeMap((error: HttpErrorResponse, retryAttempt: number) => {
            if (retryAttempt === 3 - 1) {
              console.log(`HTTP call failed after 3 retries.`);
              return throwError(error); // no retry
            }
            switch (error.status) {
              case 400:
              case 404:
                return throwError(error); // no retry
            }
            return of(error); // retry
          }),
          delay(1000),
          take(3)
        )),
        catchError(this.handleError)
      );
  }
در اینجا با اضافه شدن یک mergeMap، پیش از ارسال درخواست مجدد، به اطلاعات خطای رسیده‌ی از سمت سرور دسترسی خواهیم داشت. همچنین پارامتر دوم mergeMap، شماره سعی جاری را نیز بر می‌گرداند.
در داخل mergeMap اگر یک Observable معمولی بازگشت داده شود، به معنای صدور مجوز سعی مجدد است؛ اما اگر throwError بازگشت داده شود، دقیقا در همان لحظه کار retryWhen و سعی‌های مجدد خاتمه خواهد یافت. برای مثال در اینجا پس از 2 بار سعی مجدد، اصل خطا صادر می‌شود که سبب خواهد شد قسمت catchError اجرا شود و یا روش صرفنظر کردن از خطاهای با شماره‌های 400 یا 404 را نیز مشاهده می‌کنید. برای مثال اگر از سمت سرور خطای 404 و یا «یافت نشد» صادر شد، return throwError سبب خاتمه‌ی سعی‌های مجدد و خاتمه‌ی عملیات retryWhen می‌شود.


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

روش فوق را باید به ازای تک تک درخواست‌های HTTP برنامه تکرار کنیم. برای مدیریت یک چنین اعمال تکراری در برنامه‌های Angular می‌توان یک HttpInterceptor سفارشی را تدارک دید و توسط آن تمام درخواست‌های HTTP سراسر برنامه را به صورت متمرکز تحت نظر قرار داد:
import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from "@angular/common/http";
import { Injectable } from "@angular/core";
import { Observable, of, throwError } from "rxjs";
import { catchError, delay, mergeMap, retryWhen, take } from "rxjs/operators";

@Injectable()
export class RetryInterceptor implements HttpInterceptor {

  private delayBetweenRetriesMs = 1000;
  private numberOfRetries = 3;

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request).pipe(
      retryWhen(errors => errors.pipe(
        mergeMap((error: HttpErrorResponse, retryAttempt: number) => {
          if (retryAttempt === this.numberOfRetries - 1) {
            console.log(`HTTP call '${request.method} ${request.url}' failed after ${this.numberOfRetries} retries.`);
            return throwError(error); // no retry
          }

          switch (error.status) {
            case 400:
            case 404:
              return throwError(error); // no retry
          }

          return of(error); // retry
        }),
        delay(this.delayBetweenRetriesMs),
        take(this.numberOfRetries)
      )),
      catchError((error: any, caught: Observable<HttpEvent<any>>) => {
        console.error({ error, caught });
        if (error.status === 401 || error.status === 403) {
          // this.router.navigate(["/accessDenied"]);
        }
        return throwError(error);
      })
    );
  }
}
RetryInterceptor فوق، تمام درخواست‌های با شکست مواجه شده را دو بار با فاصله زمانی یک ثانیه تکرار می‌کند. البته در این بین همانطور که توضیح داده شد، از خطاهای 400 و 404 صرفنظر خواهد شد. همچنین در پایان کار اگر سعی‌های مجدد با موفقیت به پایان نرسند، قسمت catchError، اصل خطای رخ داده را دریافت می‌کند که در اینجا نیز می‌توان به این خطا عکس العمل نشان داد.
روش ثبت آن در قسمت providers مربوط به core.module.ts به صورت زیر است:
providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: RetryInterceptor,
      multi: true
    },
مطالب
فلسفه وجودی Path.Combine

عموما اکثر کدهای موجود از روش زیر برای ساخت یک مسیر استفاده می‌کنند:
string path = somePath + "\\" + filename;

اما اگر همین برنامه تحت Mono در لینوکس اجرا شود به مشکل بر می‌خورد زیرا در لینوکس مسیرها این‌بار به صورت زیر هستند:
/somepath/filename

به همین جهت توصیه شده است برای ساخت مسیرها در برنامه‌ی خود، از متد Path.Combine موجود در فضای نام System.IO استفاده کنید زیرا این متد از مقادیر Path.DirectorySeperatorChar و Path.VolumeSeparatorChar جهت تهیه مسیر نهایی استفاده می‌کند. این مقادیر در ویندوز (\) و لینوکس (/) متفاوت بوده و به صورت خودکار در زمان اجرا توسط فریم ورک مورد استفاده مدیریت خواهند شد.
همچنین مزیت دیگر استفاده از Path.Combine ، تعیین اعتبار ورودی است؛ به این معنا که اگر از کاراکترهای غیرمجاز استفاده شود، یک استثناء صادر خواهد شد.

یک مورد دیگر هم شاید بد نباشد همینجا اضافه شود و آن هم فلسفه وجودی Environment.NewLine است. مطابق معمول رسم بر این است که سطر جدید با n\ در انتهای یک رشته مشخص شود اما این همیشه صحیح نیست و در پلتفرم‌های مختلف متفاوت است. Environment.NewLine در ویندوز مساوی r\n\ است و در سیستم‌های مبتنی بر Unix مساوی n\ خواهد بود. به همین جهت بهتر است از این پس بجای n\ از Environment.NewLine جهت مشخص سازی سطر جدید استفاده کنید.

مطالب
شروع به کار با Ember.js
Ember.js کتابخانه‌ای است جهت ساده سازی تولید برنامه‌های تک صفحه‌ای وب. برنامه‌هایی که شبیه به برنامه‌های دسکتاپ در مرورگر کاربر عمل می‌کنند. دو برنامه نویس اصلی آن Yehuda Katz که عضو اصلی تیم‌های jQuery و Ruby on Rails است و Tom Dale که ابتدا SproutCore را به وجود آورد و بعدها به Ember.js تغییر نام یافت، هستند.

منابع اصلی Ember.js

پیش از شروع به بحث نیاز است با تعدادی از سایت‌های اصلی مرتبط با Ember.js آشنا شد:
سایت اصلی: http://emberjs.com
مخزن کدهای آن: https://github.com/emberjs
انجمن اختصاصی پرسش و پاسخ: http://discuss.emberjs.com
موتور قالب‌های آن: http://handlebarsjs.com
لیست منابع مطالعاتی مرتبط مانند ویدیوهای آموزشی و لیست مقالات موجود: http://emberwatch.com
و بسته‌ی نیوگت آن: https://www.nuget.org/packages/EmberJS



مفاهیم پایه‌ای Ember.js

شیء Application
 App = Ember.Application.create();
یک برنامه‌ی Ember.js با تعریف وهله‌ای از شیء Application آن آغاز می‌شود. با اینکار به صورت خودکار رویدادگردان‌هایی به صفحه اضافه می‌شوند. کامپوننت‌های پیش فرض آن ایجاد شده و همچنین قالب اصلی برنامه رندر می‌شود.

مسیر یابی
با مرور قسمت‌های مختلف برنامه توسط کاربر، نیاز است حالات برنامه را مدیریت کرد؛ اینجا است که کار قسمت مسیریابی شروع می‌شود. مسیریابی، منابع مورد نیاز جهت آدرس‌های مشخصی را تامین می‌کند.
App.Router.map(function() {
    this.resource('accounts'); // takes us to /accounts
    this.resource('gallery'); // takes us to /gallery
});
در اینجا نحوه‌ی تعریف آغازین مسیریابی Ember.js را مشاهده می‌کنید که توسط متد resource آن مسیرهای قابل ارائه توسط برنامه مشخص می‌شوند.
به این ترتیب مسیرهای accounts/ و gallery/ قابل پردازش خواهند شد.

این مسیرها، تو در تو نیز می‌توانند باشند. برای مثال:
App.Router.map(function() {
    this.resource('news', function() {
        this.resource('images', function () { // takes us to /news/images
            this.route('add');// takes us to /news/images/add
        });
    });
});
به این ترتیب نحوه‌ی تعریف مسیریابی آدرس news/images/add را مشاهده می‌کنید. همچنین در این مثال از دو متد resource و route استفاده شده‌است. از متد resource برای حالت تعریف اسامی استفاده کنید و از متد route برای تعریف افعال و تغییر دهنده‌ها. برای نمونه در اینجا فعل افزودن تصاویر با متد route مشخص شده‌است.


مدل‌ها
مدل‌ها همان اشیایی هستند که برنامه مورد استفاده قرار می‌دهد و می‌توانند یک آرایه‌ی ساده و یا اشیاء JSON دریافتی از وب سرور باشند.
حداقل به دو روش می‌توان مدل‌ها را تعریف کرد:
الف) با استفاده از افزونه‌ی Ember Data
ب) با کمک شیء Ember.Object
App.SiteLink = Ember.Object.extend({});
App.SiteLink.reopenClass({
    findAll: function() {
        var links = [];
        //… $.getJSON …

        return links;
    }
});
ابتدا یک زیرکلاس از Ember.Object به کمک متد extend ایجاد خواهد شد. سپس از متد توکار reopenClass برای توسعه‌ی API کمک خواهیم گرفت.
در ادامه متد دلخواهی را ایجاد کرده و برای مثال آرایه‌ای از اشیاء دلخواه جاوا اسکریپتی را بازگشت خواهیم داد.
پس از تعریف مدل، نیاز است آن‌را به سیستم مسیریابی معرفی کرد:
App.GalleryRoute = Ember.Route.extend({
    model: function() {
        return App.SiteLink.findAll();
    }
});
به این ترتیب زمانیکه کاربر به آدرس gallery/ مراجعه می‌کند، دسترسی به model وجود خواهد داشت. در اینجا model یک واژه‌ی کلیدی است.


کنترلرها
کنترلرها جهت ارائه‌ی اطلاعات مدل‌ها به View و قالب برنامه تعریف می‌شوند. در اینجا همیشه باید بخاطر داشت که model تامین کننده‌ی اطلاعات است. کنترلر جهت در معرض دید قرار دادن این اطلاعات، به View برنامه کاربرد دارد و مدل‌ها هیچ اطلاعی از وجود کنترلرها ندارند.
کنترلرها علاوه بر اطلاعات model، می‌توانند حاوی یک سری خواص و اشیاء صرفا نمایشی که قرار نیست در بانک اطلاعاتی ذخیره شوند نیز باشند.
در Ember.js قالب‌ها (templates) اطلاعات خود را از کنترلر دریافت می‌کنند. کنترلرها اطلاعات مدل را به همراه سایر خواص نمایشی مورد نیاز در اختیار View و قالب‌های برنامه قرار می‌دهند.


برای تعریف یک کنترلر می‌توان درون شیء مسیریابی، با تعریف متد setupController شروع کرد:
App.GalleryRoute = Ember.Route.extend({
    setupController: function(controller) {
        controller.set('content', ['red', 'yellow', 'blue']);
    }
});
در این مثال یک خاصیت دلخواه به نام content تعریف و سپس آرایه‌ای به آن انتساب داده شده‌است.

روش دوم تعریف کنترلرها با ایجاد یک زیر کلاس از شیء Ember.Controller انجام می‌شود:
App.GalleryController = Ember.Controller.extend({
    search: '',
    content: ['red', 'yellow', 'blue'],
    query: function() {
        var data = this.get('search');
        this.transitionToRoute('search', { query: data });
    }
});


قالب‌ها یا templates
قالب‌ها قسمت‌های اصلی رابط کاربری را تشکیل خواهند داد. در اینجا از کتابخانه‌ای به نام handlebars برای تهیه قالب‌های سمت کاربر کمک گرفته می‌شود.
<script type="text/x-handlebars" data-template-name="sayhello">
    Hello,
    <strong>{{firstName}} {{lastName}}</strong>!
</script>
این قالب‌ها توسط تگ اسکریپت تعریف شده و نوع آن‌ها text/x-handlebars مشخص می‌شود. به این ترتیب Ember.js، این قسمت از صفحه را یافته و عبارات داخل {{}} را با مقادیر دریافتی از کنترلر جایگزین می‌کند.
<script type="text/x-handlebars" data-template-name="sayhello">
    Hello,
    <strong>{{firstName}} {{lastName}}</strong>!
 
    {{#if person}}
    Welcome back,
    <strong>{{person.firstName}} {{person.lastName}}</strong>!
    {{/if}}
 
    <ul>
        {{#each friend in friends}}
        <li>
            {{friend.name}}
        </li>
        {{/each}}
    </ul>
 
    <img {{bindAttr src="link.url" }} />
    {{#linkTo ''about}}About{{/linkTo}}
</script>
در این مثال نحوه‌ی تعریف عبارات شرطی و یا یک حلقه را نیز مشاهده می‌کنید. همچنین امکان اتصال به ویژگی‌هایی مانند src یک تصویر و یا ایجاد لینک‌ها را نیز دارا است.
بهترین مرجع آشنایی با ریز جزئیات کتابخانه‌ی handlebars، مراجعه به سایت اصلی آن است.


قواعد پیش فرض نامگذاری در Ember.js
اگر به مثال‌های فوق دقت کرده باشید، خواصی مانند GalleryController و یا GalleryRoute به شیء App اضافه شده‌اند. این نوع نامگذاری‌ها در ember.js بر اساس روش convention over configuration کار می‌کنند. برای نمونه اگر مسیریابی خاصی را به نحو ذیل تعریف کردید:
 this.resource('employees');
شیء مسیریابی آن App.EmployeesRoute
کنترلر آن App.EmployeesController
مدل آن App.Employee
View آن App.EmployeesView
و قالب آن employees
بهتر است تعریف شوند. به عبارتی اگر اینگونه تعریف شوند، به صورت خودکار توسط Ember.js یافت شده و هر کدام با مسئولیت‌های خاص مرتبط با آن‌ها پردازش می‌شوند و همچنین ارتباطات بین آن‌ها به صورت خودکار برقرار خواهد شد. به این ترتیب برنامه نظم بهتری خواهد یافت. با یک نگاه می‌توان قسمت‌های مختلف را تشخیص داد و همچنین کدنویسی پردازش و اتصال قسمت‌های مختلف برنامه نیز به شدت کاهش می‌یابد.


تهیه‌ی اولین برنامه‌ی Ember.js
تا اینجا نگاهی مقدماتی داشتیم به اجزای تشکیل دهنده‌ی هسته‌ی Ember.js. در ادامه مثال ساده‌ای را جهت نمایش ساختار ابتدایی یک برنامه‌ی Ember.js، بررسی خواهیم کرد.
بسته‌ی Ember.js را همانطور که در قسمت منابع اصلی آن در ابتدای بحث عنوان شد، می‌توانید از سایت و یا مخزن کد آن دریافت کنید و یا اگر از VS.NET استفاده می‌کنید، تنها کافی است دستور ذیل را صادر نمائید:
 PM> Install-Package EmberJS
پس از اضافه شدن فایل‌های js آن به پوشه‌ی Scripts برنامه، در همان پوشه‌، فایل جدید Scripts\app.js را نیز اضافه کنید. از آن برای افزودن تعاریف کدهای Ember.js استفاده خواهیم کرد.
در این حالت ترتیب تعریف اسکریپت‌های مورد نیاز صفحه به صورت ذیل خواهند بود:
<script src="Scripts/jquery-2.1.1.js" type="text/javascript"></script>
<script src="Scripts/handlebars.js" type="text/javascript"></script>
<script src="Scripts/ember.js" type="text/javascript"></script>
<script src="Scripts/app.js" type="text/javascript"></script>
کدهای ابتدایی فایل app.js جهت وهله سازی شیء Application و سپس تعریف مسیریابی صفحه‌ی index بر اساس روش convention over configuration به همراه تعریف یک کنترلر و افزودن متغیری به نام content به آن که با یک آرایه مقدار دهی شده‌است:
App = Ember.Application.create();
App.IndexRoute = Ember.Route.extend({
    setupController:function(controller) {
        controller.set('content', ['red', 'yellow', 'blue']);
    }
});
باید دقت داشت که تعریف مقدماتی Ember.Application.create به همراه یک سری تنظیمات پیش فرض نیز هست. برای مثال مسیریابی index به صورت خودکار به نحو ذیل توسط آن تعریف خواهد شد و نیازی به تعریف مجدد آن نیست:
App.Router.map(function() {
    this.resource('application'); 
    this.resource('index');
});
سپس برای اتصال این کنترلر به یک template خواهیم داشت:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <script src="Scripts/jquery-2.1.1.js" type="text/javascript"></script>
    <script src="Scripts/handlebars.js" type="text/javascript"></script>
    <script src="Scripts/ember.js" type="text/javascript"></script>
    <script src="Scripts/app.js" type="text/javascript"></script>
</head>
<body>
    <script type="text/x-handlebars" data-template-name="index">
        Hello,
        <strong>Welcome to Ember.js</strong>!
        <ul>
            {{#each item in content}}
            <li>
                {{item}}
            </li>
            {{/each}}
        </ul>
    </script>
</body>
</html>
توسط اسکریپتی از نوع text/x-handlebars، اطلاعات آرایه content دریافت و در طی یک حلقه در صفحه نمایش داده خواهد شد.
مقدار data-template-name در اینجا مهم است. اگر آن‌را به هر نام دیگری بجز index تنظیم کنید، منبع دریافت اطلاعات آن مشخص نخواهد بود. نام index در اینجا به معنای اتصال این قالب به اطلاعات ارائه شده توسط کنترلر index است.

تا همینجا اگر برنامه را اجرا کنید، به خوبی کار خواهد کرد. نکته‌ی دیگری که در مورد قالب‌های Ember.js قابل توجه هستند، قالب پیش فرض application است. با تعریف Ember.Application.create یک چنین قالبی نیز به ابتدای هر صفحه به صورت خودکار اضافه خواهد شد:
<body>
    <script type="text/x-handlebars" data-template-name="application">
        <h1>Header</h1>
        {{outlet}}
    </script>
outlet واژه‌‌ای است کلیدی که سبب رندر سایر قالب‌های تعریف شده در صفحه می‌گردد. مقدار data-template-name آن نیز به application تنظیم شده‌است (اگر این مقدار ذکر نگردد نیز به صورت خودکار از application استفاده می‌شود). برای مثال اگر بخواهید به تمام قالب‌های رندر شده در صفحات مختلف، مقدار ثابتی را اضافه کنید (مانند هدر یا منو)، می‌توان قالب application را به صورت دستی به نحو فوق اضافه کرد و آن‌را سفارشی سازی نمود.



کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید:
EmberJS01.zip
نظرات مطالب
روش بهینه نمایش عکس در Xamarin Forms
تجربه ای در این زمینه ندارم، ولی با همین مسیر کلی که عرض کردم و مثال Xamarin Forms اش رو پیاده سازی کردم، قطعا باید بتونید راه حلی پیدا کنید. یعنی عکس رو به صورت svg داشته باشید و ابزاری به صورت خودکار اون رو به پنج حالت اصلی تبدیل کنه و پنج تا png نشون بده و تو فولدرهای مربوطه تو پروژه اندروید بگذاره و نمایش عکس کار کنه. البته توی Hybrid دیگه استفاده از Glide و Nuke معنی نمیده، ولی در عوض اگه هدف پشتیبانی از دستگاه‌های خیلی قدیمی نباشه، خود svg‌ها رو هم میشه نشون داد.
پاسخ به بازخورد‌های پروژه‌ها
مشکل با نوشتن تابع تجمعی سفارشی(از طریق پیاده سازی IAggregateFunction)
ببخشید، یه سوال دیگه!
در یه گزارش دیگه به جای مانده تجمعی مانده سطری دارم یعنی(درهرسطر(بدهکار - بستانکار)میشه و در ستون مانده قرار می‌گیره و ستون تشخیص هم با توجه به همان سطر است)
بنابراین دیگه مثل گزارش قبلی نمیتونم از تابع تجمعی استفاده کنم.
میخوام ببینم چطور میشه، جاهایی که در عکس highlight کردم رو(یعنی سطرهای خلاصه صفحه و خلاصه کل)،
مقدار دهی کنم، در عکس با توجه به اینکه جمع کل بدهکار یعنی ستون اول از جمع کل بستانکار یعنی ستون دوم بیشتره، بنابراین مقدار قسمت‌های highlight شده نیز باید "بدهکار" باشد.

بازخوردهای پروژه‌ها
ویرایشگر متن
با سلام 
مشکلی که بنده دارم ظاهرا برای حرفه ای‌های وب حل شده است
بنده نیاز به  معرفی و آموزش یک ویرایشگر متن آنلاین با قابلیت ارسال عکس (رایگان) و ساده دارم اگر امکان دارد در این آموزش موارد زیر پوشش داده شود
آموزش در محیط ASP.NET MVC باشد
آموزش ارسال عکس و فایل به صورت مفصل باشد 
امکاناتی همچون تغییر فونت پیش فرض , تنظیم فاصله بین خطوط , امکان راست چین کردن متن و کم و زیاد کردن جعبه ابزار نیز در این آموزش در نظر گرفته شود
در آخر فایل پروژه هم ضمیمه آموزش باشد
با تشکر
بازخوردهای پروژه‌ها
سوال
سلام 
من یک فروشگاه طراحی کردم حالا می‌خواهم یک سری امکانات به آن اضافه کنم در صورت امکان بنده را راهنمایی کنید با تشکر 
1.برای هر کالایی من یک عکس آژلود می‌کردم در صورتی که بخواهم تعداد  عکس کالا بیش از یک باشد مثلا 4 یا 5 یا 6 به دلخواه کاربر آیا باید جدولی جدیدی به پروژه اصافه بشه که به جدول کالا‌ها ریلشن بشه .
2.کاربر قبل از لاگین و یا قبل از عضویت شروع به خرید میکنه حالا این مکانیزم به چه شکل داره اتفاق میفته .
نظرات مطالب
فعال سازی قسمت ارسال فایل و تصویر ویرایشگر آنلاین RedActor در ASP.NET MVC
درسته. علت این است که پوشه App_Data محافظت شده است و از طریق فراخوانی لینک آن به صورت مستقیم قابل دسترسی نیست.
اگر فایل‌ها رو در این پوشه ارسال می‌کنید نیاز هست مثلا یک کنترلر دیگر به نام file درست کنید و کار این کنترلر فایل، دریافت نام تصویر و ارسال آن به صورت return File به مرورگر کاربر باشد.
یا اینکه کلا از یک پوشه معمولی استفاده کنید.
+
ضمن اینکه کاراکتر ~ برای تگ معمولی img مفهومی ندارد و نباید از آن در پایان کار استفاده شود.