نظرات مطالب
مستند سازی ASP.NET Core 2x API توسط OpenAPI Swagger - قسمت هفتم - سفارشی سازی ظاهر مستندات API
ابتدا باید آن‌ها را گروه بندی کنید:
[HttpPost]
[ApiExplorerSettings(GroupName = "v2")]
public void Post([FromBody]Product product)
و بعد endpointهای متفاوتی را تعریف کنید:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// ....

   services.AddSwaggerGen(c =>
   {
     c.SwaggerDoc("v1", new Info { Title = "My API - V1", Version = "v1" });
     c.SwaggerDoc("v2", new Info { Title = "My API - V2", Version = "v2" });
   });

   // ....
}

public void Configure(IApplicationBuilder app)
{
   // ....

   app.UseSwaggerUI(options =>
   {
     options.SwaggerEndpoint("/swagger/v1/swagger.json", "AbpProjectName API V1");
     options.SwaggerEndpoint("/swagger/v2/swagger.json", "AbpProjectName API V2");
   }

  // ....
}
مطالب
Minimal API's در دات نت 6 - قسمت پنجم - پیاده سازی الگوی CQRS
تا قسمت قبل موفق شدیم فایل Program.cs برنامه‌ی Minimal API's را خلوت کنیم و همچنین زیرساختی را برای توسعه‌ی مبتنی بر ویژگی‌ها، ارائه دهیم. اما ... هنوز endpoints ما چنین شکلی را دارند:
        endpoints.MapGet("/api/authors", async (MinimalBlogDbContext ctx) =>
        {
            var authors = await ctx.Authors.ToListAsync();
            return authors;
        });

        endpoints.MapPost("/api/authors", async (MinimalBlogDbContext ctx, AuthorDto authorDto) =>
        {
            var author = new Author();
            author.FirstName = authorDto.FirstName;
            author.LastName = authorDto.LastName;
            author.Bio = authorDto.Bio;
            author.DateOfBirth = authorDto.DateOfBirth;

            ctx.Authors.Add(author);
            await ctx.SaveChangesAsync();

            return author;
        });
 و یک چنین رویه‌ای جهت کار مستقیم با DbContext در اکشن متدهای MVC هیچگاه توصیه نمی‌شود. برای مثال به طور معمول، عملیاتی که در بدنه‌ی Lambda expressions فوق انجام شده، عموما به Repositories و Services محول شده و در نهایت از سرویس‌ها، در اکشن متدها استفاده می‌شود. در معماری جاری که در پیش گرفته‌ایم، دو لایه‌ی Repositories و Services حذف شده‌اند و دیگر خبری از آن‌ها نیست. در اینجا کار سرویس‌ها و مخازن، به هندلرهای معماری CQRS واگذار خواهند شد. هر هندلر نیز متکی به خود است و مستقل از سایر هندلرها طراحی می‌شود و این‌ها صرفا بر اساس نیازهای ویژگی جاری توسعه خواهند یافت و دقیقا در همان پوشه‌ی ویژگی مورد بررسی نیز قرار می‌گیرند؛ و نه پراکنده در لایه‌ای و یا پروژه‌ای دیگر. به این ترتیب درک یک ویژگی متکی به خود برنامه، ساده‌تر شده و در طول زمان، نگهداری و توسعه‌ی آن نیز ساده‌تر خواهد شد. مشکل داشتن سرویس‌هایی بزرگ که در معماری‌های متداول وجود دارند، استفاده‌ی از متدهای آن‌ها در چندین اکشن متد و چندین کنترلر مختلف است و اگر یکی از متدهای این سرویس بزرگ ما تغییر کند، بر روی چندین کنترلر تاثیر می‌گذارد که ممکن است سبب از کار افتادگی بعضی از آن‌ها شود؛ اما در اینجا هرکاری که انجام می‌شود و هر هندلری که توسعه می‌یابد، فقط مختص به یک کار و یک ویژگی مشخص است.


ایجاد Command و هندلر مخصوص ایجاد یک نویسنده‌ی جدید


در الگوی CQRS، یک دستور، کاری را بر روی بانک اطلاعاتی انجام می‌دهد. برای مثال در اینجا قرار است نویسنده‌ای را ثبت کند. در ادامه می‌خواهیم بدنه‌ی endpoints.MapPost فوق را با الگوی CQRS انطباق دهیم. به همین جهت به یک Command نیاز داریم:
using MediatR;
using MinimalBlog.Domain.Model;

namespace MinimalBlog.Api.Features.Authors;

public class CreateAuthorCommand : IRequest<Author>
{
    public AuthorDto AuthorDto { get; set; } = default!;
}
اینترفیس IRequest کتابخانه‌ی MediatR که در انتهای قسمت قبل به پروژه اضافه شد، چنین امضایی را دارد:
public interface IRequest<out TResponse> : IBaseRequest
یعنی <IRequest<Author به این معنا است که قرار است «خروجی» این عملیات، یک Author باشد و CreateAuthorCommand می‌تواند شامل تمام خواصی باشد که در جهت برآورده کردن این دستور مورد نیاز هستند؛ برای مثال کل اطلاعات شیء AuthorDto در اینجا.

سپس نیاز به یک هندلر است تا دستور رسیده را پردازش کند:
namespace MinimalBlog.Api.Features.Authors;

public class CreateAuthorCommandHandler : IRequestHandler<CreateAuthorCommand, Author>
{
    private readonly MinimalBlogDbContext _context;
    private readonly IMapper _mapper;

    public CreateAuthorCommandHandler(MinimalBlogDbContext context, IMapper mapper)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
        _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
    }

    public async Task<Author> Handle(CreateAuthorCommand request, CancellationToken cancellationToken)
    {
        if (request == null)
        {
            throw new ArgumentNullException(nameof(request));
        }

        var toAdd = _mapper.Map<Author>(request.AuthorDto);
        _context.Authors.Add(toAdd);
        await _context.SaveChangesAsync(cancellationToken);
        return toAdd;
    }
}
اینترفیس IRequestHandler چنین امضایی را دارد:
public interface IRequestHandler<in TRequest, TResponse> where TRequest : IRequest<TResponse>
که اولین آرگومان جنریک آن، همان Command ای است که قرار است پردازش کند و خروجی آن، اطلاعاتی است که قرار است بازگشت دهد. یعنی متد Handle فوق، قرار است عملیات endpoints.MapPost را پیاده سازی کند و در اینجا با استفاده از AutoMapper، انتساب‌های آن حذف و ساده شده‌اند و مابقی آن، با بدنه‌ی lambda expression مربوط به endpoints.MapPost، یکی است. این هندلر، معادل یک یا چند متد از متدهای یک سرویس بزرگ است که در اینجا به صورت اختصاصی جهت پردازش فرمانی در کنار هم قرار می‌گیرند و متکی به خود هستند.

پس از این تغییرات، بدنه‌ی lambda expression مربوط به endpoints.MapPost به صورت زیر تغییر کرده و ساده می‌شود:
endpoints.MapPost("/api/authors", async (IMediator mediator, AuthorDto authorDto) =>
{
     var command = new CreateAuthorCommand { AuthorDto = authorDto };
     var author = await mediator.Send(command);
     return author;
});
در اینجا تزریق وابستگی IMediator را مشاهده می‌کنید. با فراخوانی متد Send آن، شیء‌ای به هندلر متناظری ارسال شده، پردازش می‌شود و در نهایت شیءای را بازگشت خواهد داد. برای مثال در اینجا شیء Dto یک نویسنده به هندلر CreateAuthorCommandHandler ارسال و تبدیل به شیءای از نوع Author مربوط به دومین برنامه شده، سپس در بانک اطلاعاتی ذخیره می‌شود و در نهایت این نویسنده که اکنون به همراه یک Id نیز هست، بازگشت داده می‌شود. بنابراین هر هندلر یک object in و یک object out دارد که به عنوان آرگومان‌های جنریک IRequestHandler تعریف می‌شوند.



نکته 1: await داخل بدنه‌ی lambda expression مربوط به endpoints را فراموش نکنید. تمام متدهای IMediator از نوع aysnc هستند؛ هرچند روش نامگذاری SendAsync را رعایت نکرده‌اند و اگر این await فراموش شود، مشاهده خواهید کرد که برنامه در حین فراخوانی endpoints در مرورگر، در حالت هنگ و صبر کردن نامحدود قرار می‌گیرد، بدون اینکه کاری را انجام دهد و یا حتی استثنایی را صادر کند.


نکته 2: در پیاده سازی هندلر، استفاده از cancellationToken را نیز مشاهده می‌کنید. تقریبا تمام متدهای async مربوط به EF-Core به همراه پارامتری جهت دریافت cancellationToken هم هستند. اگر کاربری قصد لغو یک درخواست طولانی را داشته باشد و بر روی دکمه‌ی stop مرورگر کلیک کند و یا حتی صفحه را چندین بار ریفرش کند، این به معنای abort درخواست(های) رسیده‌است. وجود این cancellationTokenها، بار سرور را کاهش داده و عملیات در حال اجرای سمت سرور را در یک چنین حالت‌هایی متوقف می‌کند.
البته هندلری که در اینجا تعریف شده، این cancellationToken را باید از mediator دریافت کند که در کدهای endpoint فوق، چنین نیست. برای رفع این مشکل باید به صورت زیر عمل کرد:
endpoints.MapGet("/api/authors", async (IMediator mediator, CancellationToken ct) =>
        {
            var request = new GetAllAuthorsQuery();
            var authors = await mediator.Send(request, ct);
            return authors;
        });
این مورد را می‌توان به صورت یک best practice، به تمام endpoints اضافه کرد.


نکته 3: هندلرها عموما چیزی را بازگشت نمی‌دهند؛ صرف نظر از هندلر فوق که نیاز بوده تا Id شیء ذخیره شده را بازگشت دهد، عموما به همراه هیچ خروجی نیستند. به همین جهت در حین تعریف آن‌ها فقط کافی است در آرگومان‌های جنریک آن‌ها، نوع خروجی را ذکر نکنیم:
public class Handler : IRequestHandler<Command>
در یک چنین حالتی، امضای IRequestHandler به صورت خودکار به همراه خروجی از نوع Unit خواهد بود:
public interface IRequestHandler<in TRequest> : IRequestHandler<TRequest, Unit> where TRequest : IRequest<Unit>
که این Unit معادل Void در کتابخانه‌ی mediator است و به نحو زیر در هندلرها مدیریت می‌شود:
public async Task<Unit> Handle(Command request, CancellationToken cancellationToken)
{
   // ...
   return Unit.Value;
}
در یک چنین حالتی، تعریف یک Command نیز بر اساس اینترفیس IRequest انجام می‌شود:
public class Command : IRequest


ایجاد Query و هندلر مخصوص بازگشت لیست نویسنده‌‌ها

در الگوی CQRS، یک کوئری قرار است اطلاعاتی را بازگشت دهد و ... وضعیت بانک اطلاعاتی را تغییر نمی‌دهد. بنابراین در اینجا یک IRequest که قرار است لیستی از نویسندگان را بازگشت دهد، تعریف می‌کنیم. بدنه‌ی آن هم می‌تواند خالی باشد و یا به همراه خواصی مانند اطلاعات صفحه بندی و یا مرتب سازی گزارشگیری رسیده‌ی از درخواست:
using MediatR;
using MinimalBlog.Domain.Model;

namespace MinimalBlog.Api.Features.Authors;

public class GetAllAuthorsQuery : IRequest<List<Author>>
{
}
سپس نیاز به یک هندلر است تا درخواست رسیده را پردازش کند. این هندلر، کوئری فوق را دریافت کرده و لیست کاربران را بازگشت می‌دهد:
namespace MinimalBlog.Api.Features.Authors;

public class GetAllAuthorsHandler : IRequestHandler<GetAllAuthorsQuery, List<Author>>
{
    private readonly MinimalBlogDbContext _context;

    public GetAllAuthorsHandler(MinimalBlogDbContext context)
    {
        _context = context ?? throw new ArgumentNullException(nameof(context));
    }

    public Task<List<Author>> Handle(GetAllAuthorsQuery request, CancellationToken cancellationToken)
    {
        return _context.Authors.ToListAsync(cancellationToken);
    }
}
پس از این تغییرات، بدنه‌ی lambda expression مربوط به endpoints.MapGet به صورت زیر تغییر کرده و ساده می‌شود:
endpoints.MapGet("/api/authors", async (IMediator mediator) =>
{
   var request = new GetAllAuthorsQuery();
   var authors = await mediator.Send(request);
   return authors;
});
مزیت استفاده‌ی از الگوی CQRS، تنها به حذف لایه‌ی سرویس و رسیدن به ویژگی‌هایی مستقل و متکی به خود، منحصر نیست. با استفاده از این الگو می‌توان مقیاس پذیری برنامه را نیز افزایش داد. برای مثال یک بانک اطلاعاتی بهینه سازی شده را صرفا برای کوئری‌ها، درنظر گرفت و بانک اطلاعاتی دیگری را تنها برای اعمال Write که Commands بر روی آن اجرا می‌شوند و در اینجا تنها نیاز به همگام سازی اطلاعات بانک اطلاعاتی Write، با بانک اطلاعاتی Read است که در بسیاری از اوقات پرکارتر از بانک‌های اطلاعاتی دیگر است:


و یا حتی معماری CQRS با معماری Event store نیز قابل ترکیب است:


در اینجا بجای استفاده از بانک اطلاعاتی Write، از یک Event store استفاده می‌شود. کار event store، دریافت رویدادهای write است و سپس باز پخش آن‌ها به بانک اطلاعاتی Read؛ تا کار همگام سازی به این نحو صورت گیرد.


روشی برای نظم دادن به نحوه‌ی تعریف کلاس‌های الگوی CQRS

تا اینجا برای مثال کلاسCreateAuthorCommand  را در یک فایل مجزا و سپس هندلر آن‌را به نام CreateAuthorCommandHandler در یک فایل دیگر تعریف کردیم. می‌توان جهت بالابردن خوانایی برنامه، کاهش رفت و برگشت‌ها برای یافتن کلاس‌های مرتبط و همچنین سهولت یافتن هندلرهای مرتبط با هر متد mediator.Send، از روش زیر نیز استفاده کرد:
public static class CreateAuthor
{
    public class Command : IRequest<AuthorGetDto>
    {
        // ...
    }

    public class Handler : IRequestHandler<Command, AuthorGetDto>
    {
       // ...
    }
}
در اینجا از nested classes استفاده شده‌است. ابتدا نام اصلی Command و یا کوئری ذکر می‌شود؛ که نام کلاس دربرگیرنده‌ی اصلی را تشکیل می‌دهد. سپس دو کلاس بعدی فقط Command و Handler نام می‌گیرند و نه هیچ نام دیگری. به این ترتیب به یکسری نام یک دست در کل پروژه خواهیم رسید. زمانیکه قرار است mediator.Send فراخوانی شود، اینبار چنین شکلی را پیدا می‌کند که مزیت آن، سهولت یافتن هندلر مرتبط، فقط با پیگیری کلاس اصلی CreateAuthor است:
var command = new CreateAuthor.Command { AuthorDto = authorDto };
var author = await mediator.Send(command, ct);

در مورد کوئری‌ها هم می‌توان به قالب مشابهی رسید که در اینجا هم کوئری و هندلر آن، ذیل نام اصلی مدنظر قرار می‌گیرند:
public static class GetAllAuthors
{
    public class Query : IRequest<List<AuthorGetDto>>
    {
       //...
    }

    public class Handler : IRequestHandler<Query, List<AuthorGetDto>>
    {
       //...
    }
}
و اگر کدهای نهایی این سری را که از قسمت اول قابل دریافت است بررسی کنید، از همین ساختار یکدست، برای تعاریف دستورات و کوئری‌ها استفاده شده‌است.
نظرات مطالب
معرفی کتاب: مرجع کامل ASP.NET MVC 4
خیلی دنبال یک کتاب خوب بودم .
خوشحالم که قراره کتاب آقای راد رو بخونم .
مطمئنم که مثل کتاب CSS ایشون این هم کتاب فوق العاده هست .
از اینجا : http://www.pendarepars.com/book/index/137/?filter=MVC 
خریداری کردم . امیدوارم که زودتر به دستم برسه ...
نظرات مطالب
مراحل تنظیم Let's Encrypt در IIS

یک نکته‌ی تکمیلی

ACME V1 تا چند ماه دیگر به پایان خواهد رسید:
In June of 2020 we will stop allowing new domains to validate via ACMEv1.
در این حالت برای ارتقاء به نگارش 2 آن، تنها کافی است نگارش جدید win-acme را دریافت و اجرا کنید (که برای اجرا نیاز به نصب NET Core 3.1. را دارد). همچنین scheduled task قدیمی را هم که در سیستم برای نگارش 1 داشتید، disable کنید.
یک نمونه لاگ اجرای نگارش جدید آن به صورت زیر است:
 A simple Windows ACMEv2 client (WACS)
 Software version 2.1.3.671 (RELEASE, PLUGGABLE)
 IIS version 7.5
 Running with administrator credentials
 Scheduled task not configured yet
 Please report issues at https://github.com/PKISharp/win-acme

 N: Create new certificate (simple for IIS)
 M: Create new certificate (full options)
 L: List scheduled renewals
 R: Renew scheduled
 S: Renew specific
 A: Renew *all*
 O: More options...
 Q: Quit

 Please choose from the menu: m

 Running in mode: Interactive, Advanced

  Please specify how the list of domain names that will be included in the
  certificate should be determined. If you choose for one of the "all bindings"
  options, the list will automatically be updated for future renewals to
  reflect the bindings at that time.

 1: IIS
 2: Manual input
 3: CSR created by another program
 C: Abort

 How shall we determine the domain(s) to include in the certificate?: 1

  Please select which website(s) should be scanned for host names. You may
  input one or more site identifiers (comma separated) to filter by those
  sites, or alternatively leave the input empty to scan *all* websites.

 1: Default Web Site (2 bindings)

 Site identifier(s) or <ENTER> to choose all: 1

 1: dotnettips.info (Site 1)
 2: www.dotnettips.info (Site 1)

  You may either choose to include all listed bindings as host names in your
  certificate, or apply an additional filter. Different types of filters are
  available.

 1: Pick specific bindings from the list
 2: Pick bindings based on a search pattern
 3: Pick bindings based on a regular expression
 4: Pick *all* bindings

 How do you want to pick the bindings?: 4

 1: dotnettips.info (Site 1)
 2: www.dotnettips.info (Site 1)

  Please pick the most important host name from the list. This will be
  displayed to your users as the subject of the certificate.

 Common name: 2

 1: dotnettips.info (Site 1)
 2: www.dotnettips.info (Site 1)

 Continue with this selection? (y*/n)  - yes

 Target generated using plugin IIS: www.dotnettips.info and 1 alternatives

 Suggested friendly name '[IIS] Default Web Site, (any host)', press <ENTER> to
accept or type an alternative: <Enter>

  The ACME server will need to verify that you are the owner of the domain
  names that you are requesting the certificate for. This happens both during
  initial setup *and* for every future renewal. There are two main methods of
  doing so: answering specific http requests (http-01) or create specific dns
  records (dns-01). For wildcard domains the latter is the only option. Various
  additional plugins are available from https://github.com/PKISharp/win-acme/.

 1: [http-01] Save verification files on (network) path
 2: [http-01] Serve verification files from memory (recommended)
 3: [http-01] Upload verification files via FTP(S)
 4: [http-01] Upload verification files via SSH-FTP
 5: [http-01] Upload verification files via WebDav
 6: [dns-01] Create verification records manually (auto-renew not possible)
 7: [dns-01] Create verification records with acme-dns (https://github.com/joohoi/acme-dns)
 8: [dns-01] Create verification records with your own script
 9: [tls-alpn-01] Answer TLS verification request from win-acme
 C: Abort

 How would you like prove ownership for the domain(s) in the certificate?: 2

  After ownership of the domain(s) has been proven, we will create a
  Certificate Signing Request (CSR) to obtain the actual certificate. The CSR
  determines properties of the certificate like which (type of) key to use. If
  you are not sure what to pick here, RSA is the safe default.

 1: Elliptic Curve key
 2: RSA key

 What kind of private key should be used for the certificate?: 2

  When we have the certificate, you can store in one or more ways to make it
  accessible to your applications. The Windows Certificate Store is the default
  location for IIS (unless you are managing a cluster of them).

 1: IIS Central Certificate Store (.pfx per domain)
 2: PEM encoded files (Apache, nginx, etc.)
 3: Windows Certificate Store
 C: Abort

 How would you like to store the certificate?: 3

 1: IIS Central Certificate Store (.pfx per domain)
 2: PEM encoded files (Apache, nginx, etc.)
 3: No additional storage steps required
 C: Abort

 Would you like to store it in another way too?: 3

  With the certificate saved to the store(s) of your choice, you may choose one
  or more steps to update your applications, e.g. to configure the new
  thumbprint, or to update bindings.

 1: Create or update https bindings in IIS
 2: Create or update ftps bindings in IIS
 3: Start external script or program
 4: Do not run any (extra) installation steps

 Which installation step should run first?: 1

 Use different site for installation? (y/n*)  - no

 1: Create or update ftps bindings in IIS
 2: Start external script or program
 3: Do not run any (extra) installation steps

 Add another installation step?: 3

 Enter email(s) for notifications about problems and abuse (comma seperated): name@site.com

 Terms of service:   C:\ProgramData\win-acme\acme-v02.api.letsencrypt.org\LE-SA-v1.2-November-15-2017.pdf

 Open in default application? (y/n*)  - no

 Do you agree with the terms? (y*/n)  - yes

 Authorize identifier: dotnettips.info
 Authorizing dotnettips.info using http-01 validation (SelfHosting)
 Authorization result: valid
 Authorize identifier: www.dotnettips.info
 Authorizing www.dotnettips.info using http-01 validation (SelfHosting)
 Authorization result: valid
 Requesting certificate [IIS] Default Web Site, (any host)
 Store with CertificateStore...
 Installing certificate in the certificate store
 Adding certificate [IIS] Default Web Site, (any host) @ 2020/2/1 9:43:55 to store My
 Installing with IIS...
 Updating existing https binding www.dotnettips.info:443 (flags: 0)
 Updating existing https binding dotnettips.info:443 (flags: 0)
 Committing 2 https binding changes to IIS
 Adding Task Scheduler entry with the following settings
 - Name win-acme renew (acme-v02.api.letsencrypt.org)
 - Path C:\Programs\win-acme.v2.1.3.671.x64.pluggable
 - Command wacs.exe --renew --baseuri "https://acme-v02.api.letsencrypt.org/"
 - Start at 09:00:00
 - Time limit 02:00:00

 Do you want to specify the user the task will run as? (y/n*)  - no
اشتراک‌ها
ساخت دیتابیس یکبار مصرف Mongo بدون نیاز به نصب آن!

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


طرز کار با آن خیلی ساده‌است؛ فقط کافی است بسته‌ی NuGet آن را نصب کنید:

Install-Package Mongo2Go

و به صورت زیر از آن استفاده کنید:

using (var runner = MongoDbRunner.Start())
{
   var client = new MongoClient(runner.ConnectionString);
   var database = client.GetDatabase("IntegrationTest");
   var collection = database.GetCollection<TestDocument>("TestCollection");
   //Just use it!
}
ساخت دیتابیس یکبار مصرف Mongo بدون نیاز به نصب آن!
پاسخ به بازخورد‌های پروژه‌ها
بروز خطا
- نگارش 2.8، برای iTextSharp 5.5.6 تهیه نشده‌است. برای نگارش 5.5.5 آن کامپایل شده‌است. در یک چنین مواردی راه حل «به روز رسانی قسمت assemblyBinding فایل‌های config توسط NuGet» می‌تواند مفید باشد.
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="itextsharp" publicKeyToken="8354ae6d2174ddca" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-5.5.6.0" newVersion="5.5.6.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
- همچنین بسته‌ی نیوگت این کتابخانه برای iTextSharp 5.5.6 به روز شد. بنابراین دستور ذیل را صادر کنید:
PM> update-package
نظرات مطالب
ساخت بسته‌های نیوگت مخصوص NET Core.
ساخت بسته‌ی نیوگت مخصوص NET Core. و همچنین NET 4.x. (در قالب یک فایل و یک بسته‌ی نیوگت)

نکته‌ی آن‌را در اینجا می‌توانید مطالعه کنید و خلاصه‌ی آن به صورت ذیل است:
    "frameworks": {
        "net40": {
            "frameworkAssemblies": {
            }
        },

        "net45": {
            "frameworkAssemblies": {
            }
        },

        "net46": {
            "frameworkAssemblies": {
            }
        },

        "netstandard1.3": {
            "imports": "dnxcore50",
            "dependencies": {
                "NETStandard.Library": "1.6.1",
                "System.Globalization.Extensions": "4.3.0",
                "System.Reflection": "4.3.0",
                "System.Reflection.TypeExtensions": "4.3.0"
            }
        }
    },
قسمت dependencies واقع در ریشه‌ی فایل project.json حذف شده و به ذیل قسمت netstandard انتقال پیدا می‌کند. همچنین به ازای فریم‌ورک‌های مختلف 4x مدنظر، یک مدخل مرتبط در قسمت frameworks اضافه می‌شود.
همین مقدار تغییر به همراه نکته‌ی scripts -> postcompile ابتدای بحث جاری، سبب خواهد شد تا کتابخانه‌ی جاری برای تمام فریم ورک‌های یاد شده به صورت مجزا کامپایل شده و درون بسته‌ی نیوگت نهایی قرار گیرد:


در این حالت ممکن است قسمتی از کدها مثلا برای دات نت 4 قابل استفاده نباشند و نیاز به تغییر داشته باشند. برای این حالت باید از if directives# جهت شرطی کردن کامپایلر کمک گرفت:
#if NET40
// This only compiles for the .NET Framework 4 targets
#else
// This compiles for all other targets
#endif
مطالب
مروری سریع بر neo4j
neo4j  یک بانک اطلاعاتی گراف پایه است که جزو بانک‌های اطلاعاتی no-sql طبقه بندی می‌شود. سرعت بسیار بالا و امکان اجرای کوئری‌های پیچیده، از برجسته‌ترین ویژگی‌های این بانک اطلاعاتی است. 
بهترین کاربرد neo4j  استفاده به عنوان مکمل برای بانک اطلاعاتی‌های دیگر مثل مونگو و کاساندرا است؛ به این صورت که دیتای اصلی در دیتابیس مونگو یا کاساندرا ذخیره گردد و ایندکس این دیتا‌ها به همراه چند پارامتر کلیدی که در کوئری‌ها استفاده زیادی دارد در neo4j ذخیره گردد. اکثر کوئری‌ها بر روی neo4j اجرا شوند و با استفاده از کلید‌های یافته شده، دیتای اصلی از بانک اطلاعاتی اصلی دریافت شود. این روش در پروژه‌های بسیار بزرگ (مثل شبکه‌های اجتماعی) کاربرد فراوانی دارد. همین شیوه برای استفاده از ElasticSearch نیز بسیار مرسوم است. 
برای آموزش نصب neo4j در ویندوز، از این لینک و در لینوکس از این لینک استفاده کنید.
برای کار با neo4j آدرس http://127.0.0.1:7474 را درمرورگر وارد کنید و سپس وارد ویرایشگر کوئری شوید. برای بار اول، neo4j از شما نام کاربری و رمز عبوری را درخواست می‌کند. این نام و رمز عبور، هنگام نصب تعیین می‌شود. معمولآ نام کاربری آن neo4j  است. 


در زیر برخی دستورات ابتدایی آن آورده شده است. 
ایجاد یک آبجکت و یا ویرایش آن
برای ساخت یک آبجکت و یا ویرایش آن، باید از فرم کوئری زیر استفاده کنیم. این مرحله معادل ساخت جدول در بانک‌های اطلاعاتی رابطه‌ای است. 
CREATE  (VariableName:objectType { guid: {keyInMainDB }, property1 :value1 ,property2 : value2 ,... )

فرم زیر، هم برای ایجاد کاربرد دارد و هم برای ویرایش. چون این فرم هر دو حالت را باهم پوشش می‌دهد، بیشتر استفاده می‌شود. هر چند در مواقعی که می‌خواهیم تعداد زیادی دیتا وارد بانک کنیم، حالت قبل سرعت بالاتری دارد. 
MERGE (VariableName:objectType { guid: keyInMainDB }) SET VariableName +={property1: value1,property2: value2,...}
مثال واقعی: 
MERGE (object:User { guid: 1353554 }) SET object +={username:"nasser" ,time_created: 1522480294 }
در مثال بالا یک آبجکت با نوع یوزر را ایجاد کردیم. با اینکار در واقع تایپ یوزر را هم به neo4j معرفی کردیم. البته هر اسمی را می‌توانیم جای یوزر بگذاریم. 
مقادیر عددی مستقیم، و موارد رشته‌ای با کوتیشن به خواص نسبت داده شدند‌. اسم خواص را هم ما انتخاب کردیم. علاوه بر عدد و رشته، neo4j از آرایه هم به عنوان نوع داده ورودی پشتیبانی می‌کند. 

بازیابی یک آبجکت 
برای بازیابی یک آبجکت، از فرم ساده زیر استفاده می‌شود: 
match (VariableName:objectType ) return VariableName  
برای بازیابی آبجکتی که در بالا درج شد، از مثال واقعی زیر استفاده می‌کنیم:
match (object:User { guid: 1353554 }) return object
می‌توانیم برای بازیابی شرط هم تعیین کنیم:
match (object:User ) where object.time_created>1522480293  return object

ایجاد رابطه بین دو شیء 
برای ایجاد رابطه بین دو شیء، از فرم زیر استفاده می‌کنیم: 
MATCH (v1:objectType1 {guid: guid1}),
(v2:objectType2  {guid: guid2})  
MERGE (v1)-[:RelationshipName]->(v2)
برای مثال واقعی می‌توانید حالتی را در نظر بگیرید که یک کاربر، کاربر دیگری را در شبکه اجتماعی دنبال می‌کند. در اینجا رابطه دنبال کردن بین دو کاربر ایجاد می‌شود. یا حالتی که یک فرد، یک متن یا تصویر را لایک می‌کند، در اینجا بین آبجکت کاربر و آن آبجکت متن یا تصویر، رابطه لایک کردن ایجاد می‌شود. 
مثال واقعی برای لایک کردن: 
MATCH (usr:User {guid: 1353554  }),(img:Image  {guid: 88554  }) 
MERGE (usr)-[:LIKE]->(img)
اسم LIKE را ما بر روی این رابطه گذاشتیم و البته هر اسم دیگری را نیز می‌توانستیم بگذاریم و الزامی هم برای نوشتن با حروف بزرگ نبود. فقط برای راحت‌تر تفکیک کردن از سایر نوع آبجکت‌ها، این اسم را با حرف بزرگ نوشتیم . 
برای بازیابی کاربرهایی که مواردی را  لایک کرده‌اند از فرم زیر استفاده می‌کنیم: 
MATCH (usr:User)-[r:LIKE]-() Return usr
برای بازیابی همه مواردی که لایک شده‌اند: 
MATCH ()-[r:LIKE]-(n) Return n
برای بازیابی همه مواردی که یک یوزر خاص لایک کرده‌است: 
MATCH (usr:User{guid:1353554 })-[r:LIKE]-(n) Return n
برای بازیابی دو طرفی که در رابطه LIKE شرکت داشته‌اند، از فرم زیر استفاده می‌کنیم:
MATCH p=()-[r:LIKE]->() RETURN p
می‌توانید قسمت شرط را هم اضافه کنید و برای مثال همه کاربرانی را که از یک تاریخ خاص ایجاد شده‌اند و چیزی را لایک کرده‌اند، بدست بیاورید:
MATCH (usr:User )-[r:LIKE]-(n) where usr.time_created>1522480293  Return usr

مطالب
به روز رسانی View ها و رویه‌های ذخیره شده در SQL server

یکی دیگر از معایب کوئری‌های select * در SQL server این است که تغییرات حاصل در فیلدهای جداول یک بانک اطلاعاتی را در view های ساخته شده از این نوع کوئری‌ها منعکس نمی‌کند.
برای مثال جدول tblTreeItems را با سه فیلد id ، parent و title در نظر بگیرید. فرض کنید بر این اساس view زیر را ساخته‌ایم:

CREATE VIEW GetData
as
SELECT * FROM tblTreeItems

اکنون به جدول فوق ، فیلد جدید isActive را اضافه می‌کنیم. پس از این عملیات اگر کوئری ساده SELECT * FROM GetData را اجرا کنیم، فیلد جدید isActive را در آن نخواهیم دید (برخلاف انتظار که می‌بایست کوئری select * رکوردهای تمام فیلدهای جدول را بر می‌گرداند. در این‌جا ممکن است مدتی وقت صرف دیباگ کردن سیستم شود که چرا تغییرات جدید اعمال نشده و چرا سیستمی که تا چند لحظه پیش داشت کار می‌کرد الان از کار افتاد!).
باید در نظر داشت که هنگام ایجاد یک view ، تصویری از تمامی فیلدهای مورد استفاده در آن زمان، جهت بالابردن کارآیی کوئری و عدم محاسبه مجدد فیلدها در جداول سیستمی ذخیره می‌گردد ( * با نام فیلدهای همان زمان ایجاد (نه زمان فعلی)، جایگزین خواهد شد). این تصویر ایستا است و با تغییر فیلدهای یک جدول به روز نخواهد شد.
برای به روز کردن view ها و stored procedures پس از تغییرات ساختاری در جداول، باید مجددا آنها را کامپایل کرد. برای این منظور راه‌های زیادی وجود دارد، برای مثال drop کردن یک view و ایجاد مجدد آن. یا باز کردن آن view در management studio (حالت alter query) و سپس فشردن دکمه F5 جهت اجرای مجدد کوئری که این‌بار بر اساس اطلاعات جدید به روز خواهد شد. یا استفاده از رویه‌های سیستمی sp_refreshview و sp_recompile که برای کامپایل مجدد view ها و رویه‌های ذخیره شده بکار می‌روند.

برای مدیریت ساده‌تر این موارد ، اسکریپت زیر تمامی view ها و رویه‌های ذخیره شده یک دیتابیس را به صورت خودکار یافته و آنها را مجددا کامپایل می‌کند: (جهت مشاهده آن نیاز به ثبت نام دارد و رایگان است)
Refreshing Views and Recompiling Stored Procs

اشتراک‌ها
تهیه Qr-Code
سلام 
یکی از مواردی که به تازگی مرسوم شده است استفاده از QR-Code‌ها است ، گاهی لازم میشود در سایتهایی که به عنوان فروشگاه طراحی میگردند برای کالاها بارکد مشخصی طراحی کرد  و یا گاهی لازم است کاربر را بدون مجبور کردن به تایپ مورد خاص به موقعیت جدید از طریق گوشی موبال هدایت کرد و یا اینکه گاهی لازم میشود نرم افزار و یا فایلی را در گوش و یا browser  شخصی آپلود کنید ، بهترین روش استفاده از این نوع کد خواهد بود .api  اصلی این برنامه در وب سایت گوگل است البته با توجه به عدم دسترسی ساده به این api تعدادی از سایتهای ایرانی و خارجی این سرویس را ارائه میدهند 

http://www.esponce.com/api-help-v1 
با استفاده از ارسال پارامترها میتوانید این عکس و یا همان کد را  تغییر دهید .
http://qr-code.ir/api/ 
این دو سایت امکانت ساده و کاملی در این خصوص ارائه میدهند.
تهیه Qr-Code