Aracılığıyla paylaş


ASP.NET Core MVC uygulamaları geliştirme

İpucu

Bu içerik, .NET Docs'ta veya çevrimdışı olarak okunabilen ücretsiz indirilebilir bir PDF olarak sağlanan ASP.NET Core ve Azure ile Modern Web Uygulamaları Mimarisi adlı e-Kitap'tan bir alıntıdır.

ASP.NET Core ve Azure e-Kitap kapak küçük resmiyle Modern Web Uygulamalarının mimarisini oluşturun.

"İlk seferde doğru yapmak önemli değil. Son seferde doğru yapmak çok önemli." - Andrew Hunt ve David Thomas

ASP.NET Core, bulut için iyileştirilmiş modern web uygulamaları oluşturmaya yönelik platformlar arası, açık kaynak bir çerçevedir. ASP.NET Core uygulamaları, bağımlılık eklemeye yönelik yerleşik destekle daha fazla test edilebilirlik ve bakım olanağı sağlayan basit ve modüler uygulamalardır. Görünüm tabanlı uygulamalara ek olarak modern web API'leri oluşturmayı destekleyen MVC ile birlikte ASP.NET Core, kurumsal web uygulamaları oluşturmanın güçlü bir çerçevesidir.

MVC ve Razor Sayfaları

ASP.NET Core MVC, web tabanlı API'ler ve uygulamalar oluşturmak için yararlı olan birçok özellik sunar. MVC terimi, kullanıcı isteklerine yanıt verme sorumluluklarını birkaç bölüme bölen bir kullanıcı arabirimi deseni olan "Model-View-Controller" anlamına gelir. Bu deseni takip etmeye ek olarak, ASP.NET Core uygulamalarınızdaki özellikleri Razor Sayfaları olarak da uygulayabilirsiniz.

Razor Pages, ASP.NET Core MVC'de yerleşiktir ve yönlendirme, model bağlama, filtreler, yetkilendirme vb. için aynı özellikleri kullanır. Ancak, Denetleyiciler, Modeller, Görünümler vb. için ayrı klasörlere ve dosyalara sahip olmak ve öznitelik tabanlı yönlendirme kullanmak yerine Razor Sayfaları tek bir klasöre ("/Sayfalar") yerleştirilir, bu klasördeki göreli konumlarına göre yönlendirilir ve istekleri denetleyici eylemleri yerine işleyicilerle işler. Sonuç olarak, Razor Sayfaları ile çalışırken, ihtiyacınız olan tüm dosyalar ve sınıflar genellikle birlikte bulunur, web projesine yayılmaz.

EShopOnWeb örnek uygulamasında MVC, Razor Pages ve ilgili desenlerin nasıl uygulandığı hakkında daha fazla bilgi edinin.

Yeni bir ASP.NET Core Uygulaması oluşturduğunuzda, oluşturmak istediğiniz uygulama türüne yönelik bir planınız olmalıdır. Yeni bir proje oluştururken, IDE'nizde veya CLI komutunu kullanarak dotnet new birkaç şablon arasından seçim yapacaksınız. En yaygın proje şablonları Boş, Web API'si, Web Uygulaması ve Web Uygulaması 'dır (Model-Görünüm Denetleyicisi). Bu kararı yalnızca bir projeyi ilk oluşturduğunuzda alabilirsiniz ancak geri alınamaz bir karar değildir. Web API projesi standart Model-View-Controller denetleyicilerini kullanır; yalnızca varsayılan olarak Görünümler'e sahip değil. Benzer şekilde, varsayılan Web Uygulaması şablonu razor sayfaları kullanır ve bu nedenle bir Görünümler klasörü de yoktur. Görünüm tabanlı davranışı desteklemek için daha sonra bu projelere bir Görünümler klasörü ekleyebilirsiniz. Web API'si ve Model-View-Controller projeleri varsayılan olarak pages klasörü içermez, ancak Razor Pages tabanlı davranışı desteklemek için daha sonra bir klasör ekleyebilirsiniz. Bu üç şablonun üç farklı tür varsayılan kullanıcı etkileşimini desteklediğini düşünebilirsiniz: veriler (web API'si), sayfa tabanlı ve görünüm tabanlı. Ancak isterseniz tek bir projede bu şablonların herhangi birini veya tümünü karıştırabilir ve eşleştirebilirsiniz.

Neden Razor Pages?

Razor Pages, Visual Studio'daki yeni web uygulamaları için varsayılan yaklaşımdır. Razor Pages, SPA dışı formlar gibi sayfa tabanlı uygulama özellikleri oluşturmanın daha basit bir yolunu sunar. Denetleyicileri ve görünümleri kullanarak, uygulamaların birçok farklı bağımlılıkla çalışan ve modelleri görüntüleyen ve birçok farklı görünüm döndüren çok büyük denetleyicilere sahip olması yaygın bir durumdu. Bu daha karmaşık bir sonuç doğurdu ve genellikle Tek Sorumluluk İlkesini veya Açık/Kapalı İlkeleri etkin bir şekilde izlemeyen denetleyicilerle sonuçlandı. Razor Pages, razor işaretlemesiyle bir web uygulamasındaki belirli bir mantıksal "sayfa" için sunucu tarafı mantığını kapsülleyerek bu sorunu giderir. Sunucu tarafı mantığı olmayan razor sayfası yalnızca razor dosyasından (örneğin, "Index.cshtml") oluşabilir. Ancak, önemsiz olmayan Razor Sayfalarının çoğu, kurala göre ".cs" uzantısına sahip Razor dosyasıyla aynı olarak adlandırılan (örneğin, "Index.cshtml.cs") ilişkili bir sayfa modeli sınıfına sahip olur.

Razor Sayfasının sayfa modeli, MVC denetleyicisinin ve görünüm modelinin sorumluluklarını birleştirir. İstekleri denetleyici eylem yöntemleriyle işlemek yerine, "OnGet()" gibi sayfa modeli işleyicileri yürütülür ve ilişkili sayfaları varsayılan olarak işlenir. Razor Pages, ASP.NET Core uygulamasında tek tek sayfalar oluşturma sürecini basitleştirirken, ASP.NET Core MVC'nin tüm mimari özelliklerini sağlamaya devam eder. Yeni sayfa tabanlı işlevler için iyi bir varsayılan seçenektir.

MVC ne zaman kullanılır?

Web API'leri oluşturuyorsanız, MVC düzeni Razor Sayfalarını kullanmaya çalışmaktan daha mantıklıdır. Projeniz yalnızca web API'sinin uç noktalarını kullanıma sunacaksa, ideal olarak Web API proje şablonundan başlamanız gerekir. Aksi takdirde, herhangi bir ASP.NET Core uygulamasına denetleyiciler ve ilişkili API uç noktaları eklemek kolaydır. Mevcut bir uygulamayı ASP.NET MVC 5 veya önceki sürümlerinden ASP.NET Core MVC'ye geçiriyorsanız ve bunu en az çabayla yapmak istiyorsanız görünüm tabanlı MVC yaklaşımını kullanın. İlk geçişi yaptıktan sonra Razor Pages'i yeni özellikler için benimsemenin veya toptan geçiş olarak benimsemenin mantıklı olup olmadığını değerlendirebilirsiniz. .NET 4.x uygulamalarını .NET 8'e taşıma hakkında daha fazla bilgi için bkz . Mevcut ASP.NET Uygulamalarını ASP.NET Core e-Kitabına Taşıma.

Web uygulamanızı Razor Sayfaları veya MVC görünümlerini kullanarak derlemeyi seçmeniz fark etmeksizin, uygulamanız benzer performansa sahip olur ve bağımlılık ekleme, filtreler, model bağlama, doğrulama vb. için destek içerir.

İstekleri yanıtlara eşleme

ASP.NET Core uygulamaları, gelen istekleri giden yanıtlarla eşler. Düşük düzeyde, bu eşleme ara yazılımla yapılır ve basit ASP.NET Core uygulamaları ve mikro hizmetleri yalnızca özel ara yazılımdan oluşabilir. ASP.NET Core MVC kullanırken rotalar, denetleyiciler ve eylemler açısından düşünerek biraz daha yüksek bir düzeyde çalışabilirsiniz. Gelen her istek uygulamanın yönlendirme tablosuyla karşılaştırılır ve eşleşen bir yol bulunursa, isteği işlemek için ilişkili eylem yöntemi (denetleyiciye ait) çağrılır. Eşleşen bir yol bulunmazsa bir hata işleyicisi (bu örnekte NotFound sonucu döndürülerek) çağrılır.

ASP.NET Core MVC uygulamaları geleneksel yolları, öznitelik yollarını veya her ikisini de kullanabilir. Geleneksel yollar kodda tanımlanır ve aşağıdaki örnekteki gibi söz dizimi kullanılarak yönlendirme kuralları belirtilir:

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
});

Bu örnekte, yönlendirme tablosuna "default" adlı bir yol eklenmiştir. , actionve idiçin yer tutucuları controllerolan bir yol şablonu tanımlar. controller ve action yer tutucuları varsayılan olarak belirtilmiştir (Home ve Indexsırasıyla) ve id yer tutucu isteğe bağlıdır (buna uygulanan "?" nedeniyle). Burada tanımlanan kural, isteğin ilk bölümünün denetleyicinin adına, ikinci bölümün eyleme karşılık geldiğini ve gerekirse üçüncü bölümün kimlik parametresini temsil etmesi gerektiğini belirtir. Geleneksel yollar genellikle istek ara yazılım işlem hattının yapılandırıldığı Program.cs gibi uygulama için tek bir yerde tanımlanır.

Öznitelik yolları, denetleyicilere ve eylemlere genel olarak belirtilmediğinde doğrudan uygulanır. Bu yaklaşım, belirli bir yönteme bakarken bunları çok daha bulunabilir hale getirme avantajına sahiptir, ancak yönlendirme bilgilerinin uygulamada tek bir yerde tutulmadığı anlamına gelir. Öznitelik yolları ile, belirli bir eylem için birden çok yolu kolayca belirtebilir ve denetleyicilerle eylemler arasındaki yolları birleştirebilirsiniz. Örneğin:

[Route("Home")]
public class HomeController : Controller
{
    [Route("")] // Combines to define the route template "Home"
    [Route("Index")] // Combines to define route template "Home/Index"
    [Route("/")] // Does not combine, defines the route template ""
    public IActionResult Index() {}
}

Yollar [HttpGet] ve benzer özniteliklerde belirtilebilir ve ayrı [Route] öznitelikleri ekleme gereğinden kaçınılabilir. Öznitelik yolları, aşağıda gösterildiği gibi denetleyici veya eylem adlarını yineleme gereksinimini azaltmak için belirteçleri de kullanabilir:

[Route("[controller]")]
public class ProductsController : Controller
{
    [Route("")] // Matches 'Products'
    [Route("Index")] // Matches 'Products/Index'
    public IActionResult Index() {}
}

Razor Sayfaları öznitelik yönlendirmeyi kullanmaz. Razor Sayfası için yönergesinin @page bir parçası olarak ek yol şablonu bilgileri belirtebilirsiniz:

@page "{id:int}"

Önceki örnekte, söz konusu sayfa bir tamsayı id parametresine sahip bir yolla eşleşti. Örneğin, kökünde /Pages bulunan Products.cshtml sayfası aşağıdaki gibi isteklere yanıt verir:

/Products/123

Belirli bir istek bir yolla eşleştirildikten sonra, ancak eylem yöntemi çağrılmadan önce, ASP.NET Core MVC istekte model bağlama ve model doğrulaması gerçekleştirir. Model bağlama, gelen HTTP verilerini çağrılacak eylem yönteminin parametreleri olarak belirtilen .NET türlerine dönüştürmekle sorumludur. Örneğin, eylem yöntemi bir int id parametre bekliyorsa, model bağlama isteğin bir parçası olarak sağlanan bir değerden bu parametreyi sağlamaya çalışır. Bunu yapmak için, model bağlaması gönderilen formdaki değerleri, yolun kendisindeki değerleri ve sorgu dizesi değerlerini arar. Bir id değer bulunduğu varsayıldığında, eylem yöntemine geçirilmeden önce tamsayıya dönüştürülür.

Modeli bağlamanın ardından ancak eylem yöntemini çağırmadan önce model doğrulaması gerçekleşir. Model doğrulama, model türünde isteğe bağlı öznitelikler kullanır ve sağlanan model nesnesinin belirli veri gereksinimlerine uygun olduğundan emin olunmasında yardımcı olabilir. Belirli değerler gerektiği gibi belirtilebilir veya belirli bir uzunluk veya sayısal aralıkla sınırlandırılabilir, vb. Doğrulama öznitelikleri belirtilirse ancak model gereksinimleriyle uyumlu değilse, ModelState.IsValid özelliği false olur ve başarısız olan doğrulama kuralları kümesi isteği yapan istemciye göndermek için kullanılabilir.

Model doğrulama kullanıyorsanız, uygulamanızın geçersiz veriler tarafından bozulmadığından emin olmak için durum değiştirme komutları gerçekleştirmeden önce modelin her zaman geçerli olup olmadığını denetlemeniz gerekir. Her eylemde bu doğrulama için kod ekleme gereğini önlemek için filtre kullanabilirsiniz. ASP.NET Core MVC filtreleri, ortak ilkelerin ve çapraz kesme endişelerinin hedeflenen bir şekilde uygulanabilmesi için istek gruplarını kesmenin bir yolunu sunar. Filtreler tek tek eylemlere, tüm denetleyicilere veya bir uygulama için genel olarak uygulanabilir.

Web API'leri için ASP.NET Core MVC, isteklerin yanıtların nasıl biçimlendirileceğini belirtmesine olanak tanıyarak içerik anlaşmasını destekler. İstekte sağlanan üst bilgilere bağlı olarak, veri döndüren eylemler yanıtı XML, JSON veya desteklenen başka bir biçimde biçimlendirecektir. Bu özellik, aynı API'nin farklı veri biçimi gereksinimlerine sahip birden çok istemci tarafından kullanılmasını sağlar.

Web API projeleri, tek tek denetleyicilere, bir temel denetleyici sınıfına veya tüm derlemeye uygulanabilen özniteliğini kullanmayı [ApiController] düşünmelidir. Bu öznitelik otomatik model doğrulama denetimi ekler ve geçersiz modele sahip tüm eylemler doğrulama hatalarının ayrıntılarını içeren bir BadRequest döndürür. Özniteliği ayrıca tüm eylemlerin geleneksel bir yol kullanmak yerine bir öznitelik yoluna sahip olmasını gerektirir ve hatalara yanıt olarak daha ayrıntılı ProblemDetails bilgileri döndürür.

Denetleyicileri denetim altında tutma

Sayfa tabanlı uygulamalar için Razor Pages, denetleyicilerin çok büyük olmasına engel olmak için harika bir iş çıkarmaktadır. Her sayfaya yalnızca işleyicilerine ayrılmış kendi dosyaları ve sınıfları verilir. Razor Sayfalarının kullanıma sunulmasından önce, birçok görünüm merkezli uygulamanın birçok farklı eylem ve görünümden sorumlu büyük denetleyici sınıfları olacaktı. Bu sınıflar doğal olarak birçok sorumluluk ve bağımlılıklara sahip olacak şekilde büyür ve bu da onları korumayı zorlaştırır. Görünüm tabanlı denetleyicilerinizin çok fazla büyüdüğünü fark ederseniz, Razor Sayfalarını kullanmak için bunları yeniden düzenlemeyi veya aracı gibi bir desen eklemeyi göz önünde bulundurun.

Ara aracı tasarım deseni, sınıflar arasındaki bağlantıyı azaltırken, aralarında iletişime izin vermek için kullanılır. ASP.NET Core MVC uygulamalarında bu desen, eylem yöntemlerinin çalışmasını yapmak için işleyiciler kullanılarak denetleyicileri daha küçük parçalara ayırmak için sıklıkla kullanılır. Popüler MediatR NuGet paketi genellikle bunu gerçekleştirmek için kullanılır. Genellikle denetleyiciler, her biri belirli bağımlılıklar gerektirebilecek birçok farklı eylem yöntemi içerir. Herhangi bir eylem için gereken tüm bağımlılık kümesi denetleyicinin oluşturucusuna geçirilmelidir. MediatR kullanılırken, bir denetleyicinin normalde sahip olacağı tek bağımlılık, aracının bir örneğidir. Her eylem daha sonra bir işleyici tarafından işlenen bir ileti göndermek için aracı örneğini kullanır. İşleyici tek bir eyleme özgüdür ve bu nedenle yalnızca bu eylemin gerektirdiği bağımlılıklara ihtiyaç duyar. MediatR kullanan bir denetleyici örneği burada gösterilmiştir:

public class OrderController : Controller
{
    private readonly IMediator _mediator;

    public OrderController(IMediator mediator)
    {
        _mediator = mediator;
    }

    [HttpGet]
    public async Task<IActionResult> MyOrders()
    {
        var viewModel = await _mediator.Send(new GetMyOrders(User.Identity.Name));
        return View(viewModel);
    }
    // other actions implemented similarly
}

EylemdeMyOrders, bir GetMyOrders iletiye Send yapılan çağrı şu sınıf tarafından işlenir:

public class GetMyOrdersHandler : IRequestHandler<GetMyOrders, IEnumerable<OrderViewModel>>
{
    private readonly IOrderRepository _orderRepository;
    public GetMyOrdersHandler(IOrderRepository orderRepository)
    {
        _orderRepository = orderRepository;
    }

  public async Task<IEnumerable<OrderViewModel>> Handle(GetMyOrders request, CancellationToken cancellationToken)
    {
        var specification = new CustomerOrdersWithItemsSpecification(request.UserName);
        var orders = await _orderRepository.ListAsync(specification);
        return orders.Select(o => new OrderViewModel
            {
                OrderDate = o.OrderDate,
                OrderItems = o.OrderItems?.Select(oi => new OrderItemViewModel()
                  {
                    PictureUrl = oi.ItemOrdered.PictureUri,
                    ProductId = oi.ItemOrdered.CatalogItemId,
                    ProductName = oi.ItemOrdered.ProductName,
                    UnitPrice = oi.UnitPrice,
                    Units = oi.Units
                  }).ToList(),
                OrderNumber = o.Id,
                ShippingAddress = o.ShipToAddress,
                Total = o.Total()
        });
    }
}

Bu yaklaşımın sonucu, denetleyicilerin çok daha küçük olması ve öncelikli olarak yönlendirme ve model bağlamaya odaklanması, tek tek işleyicilerin ise belirli bir uç nokta için gereken belirli görevlerden sorumlu olmasıdır. Bu yaklaşım, Razor Pages'in görüntüleme tabanlı denetleyicilere sağladığı avantajları API denetleyicilerine getirmeye çalışan ApiEndpoints NuGet paketi kullanılarak MediatR olmadan da elde edilebilir.

Başvurular – İstekleri Yanıtlara Eşleme

Bağımlılıklarla çalışma

ASP.NET Core' un yerleşik desteği vardır ve bağımlılık ekleme olarak bilinen bir tekniği dahili olarak kullanır. Bağımlılık ekleme, bir uygulamanın farklı bölümleri arasında gevşek bağlantı sağlayan bir tekniktir. Uygulamanın bölümlerini yalıtmak daha kolay olduğundan daha gevşek bir kavrama tercih edilir ve test veya değiştirme olanağı sağlar. Ayrıca uygulamanın bir bölümündeki değişikliğin uygulamanın başka bir yerinde beklenmedik bir etkiye sahip olma olasılığını da düşürür. Bağımlılık ekleme, bağımlılık ters çevirme ilkesini temel alır ve genellikle açık/kapalı ilkesine ulaşmanın anahtarıdır. Uygulamanızın bağımlılıklarıyla nasıl çalıştığını değerlendirirken statik yapışkan kod kokusuna dikkat edin ve "yeni tutkaldır" aforizmasını unutmayın.

Statik cling, sınıflarınızın statik yöntemlere çağrı yapması veya altyapı üzerinde yan etkileri veya bağımlılıkları olan statik özelliklere erişmesi durumunda oluşur. Örneğin, statik bir yöntemi çağıran ve veritabanına yazan bir yönteminiz varsa, yönteminiz veritabanına sıkı bir şekilde bağlanır. Bu veritabanı çağrısını bozan her şey yönteminizi bozar. Bu tür testler statik çağrılarla dalga geçmek için ticari sahte kitaplıklar gerektirdiğinden veya yalnızca bir test veritabanıyla test edilebildiğinden, bu tür yöntemlerin test edilmesi oldukça zordur. Altyapıya bağımlılığı olmayan statik çağrılar, özellikle de tamamen durum bilgisi olmayan çağrılar çağrılabilir ve bağlama veya test edilebilirlik üzerinde hiçbir etkisi yoktur (statik çağrının kendisine kod bağlamanın ötesinde).

Birçok geliştirici statik cling ve genel durum risklerini anlayabilir, ancak doğrudan örnekleme yoluyla kodlarını belirli uygulamalarla sıkı bir şekilde bir arada tutacaktır. "Yeni tutkaldır", anahtar sözcüğün kullanımına genel bir kınama değil, bu bağlamanın new bir hatırlatıcısı olarak amaçlanır. Statik yöntem çağrılarında olduğu gibi, dış bağımlılıkları olmayan yeni tür örnekleri genellikle uygulama ayrıntılarına sıkı bir şekilde kod eklemez veya testi daha zor hale getirmez. Ancak bir sınıfın örneği her başlatıldığında, belirli bir konumdaki belirli bir örneği sabit kodlamanın mantıklı olup olmadığını veya söz konusu örneği bağımlılık olarak istemenin daha iyi bir tasarım olup olmadığını düşünmek için kısa bir süre bekleyin.

Bağımlılıklarınızı bildirme

ASP.NET Core, yöntemlerin ve sınıfların bağımlılıklarını bildirerek bağımsız değişken olarak istemesi temelinde oluşturulur. ASP.NET uygulamalar genellikle Program.cs veya bir Startup sınıfta ayarlanır.

Not

.NET 6 (ve üzeri) ve Visual Studio 2022 uygulamaları için uygulamaları tamamen Program.cs yapılandırma varsayılan yaklaşımıdır. Proje şablonları, bu yeni yaklaşımı kullanmaya başlamanıza yardımcı olacak şekilde güncelleştirildi. ASP.NET Core projeleri, isterseniz yine de bir Startup sınıf kullanabilir.

Program.cs'de hizmetleri yapılandırma

Çok basit uygulamalar için bağımlılıkları kullanarak doğrudan Program.cs dosyasına WebApplicationBuilderaktarabilirsiniz. Gerekli tüm hizmetler eklendikten sonra, uygulamayı oluşturmak için oluşturucu kullanılır.

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();

var app = builder.Build();

Startup.cs'de hizmetleri yapılandırma

Startup.cs, çeşitli noktalarda bağımlılık eklemeyi destekleyecek şekilde yapılandırılmıştır. Bir sınıf kullanıyorsanız Startup , bir oluşturucu verebilirsiniz ve bu sınıf aracılığıyla bağımlılıklar isteyebilir, örneğin:

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
    }
}

sınıfı Startup , bunun için açık tür gereksinimleri olmaması açısından ilginçtir. Özel Startup bir temel sınıftan devralmaz ve belirli bir arabirim uygulamaz. Bir oluşturucu verebilir veya veremezsiniz ve oluşturucuda istediğiniz kadar parametre belirtebilirsiniz. Uygulamanız için yapılandırdığınız web konağı başlatıldığında sınıfı çağırır Startup (bir tane kullanmasını söylediyseniz) ve sınıfın gerektirdiği bağımlılıkları doldurmak için bağımlılık ekleme özelliğini Startup kullanır. Elbette, ASP.NET Core tarafından kullanılan hizmetler kapsayıcısında yapılandırılmamış parametreler isterseniz bir özel durum alırsınız, ancak kapsayıcının bildiği bağımlılıklara bağlı kaldıkça istediğiniz her şeyi isteyebilirsiniz.

Bağımlılık ekleme, Başlangıç örneğini oluşturduğunuzda başlangıçtan itibaren ASP.NET Core uygulamalarınıza yerleşik olarak eklenir. Başlangıç sınıfı için orada durmaz. Ayrıca yönteminde bağımlılık isteğinde bulunabilirsiniz Configure :

public void Configure(IApplicationBuilder app,
    IHostingEnvironment env,
    ILoggerFactory loggerFactory)
{

}

ConfigureServices yöntemi bu davranışın özel durumudur; türünde IServiceCollectionyalnızca bir parametre almalıdır. Bağımlılık eklemeyi gerçekten desteklemesi gerekmez, çünkü bir yandan services kapsayıcısına nesne eklemekle sorumludur ve diğer yandan parametresi aracılığıyla IServiceCollection şu anda yapılandırılmış olan tüm hizmetlere erişimi vardır. Bu nedenle, gerekli hizmeti parametre olarak isteyerek veya içinde ile çalışarak sınıfının her bölümündeki Startup ASP.NET Core hizmetleri koleksiyonunda ConfigureServicestanımlanan bağımlılıklarla IServiceCollection çalışabilirsiniz.

Not

Sınıfınız Startup için belirli hizmetlerin kullanılabilir olduğundan emin olmanız gerekiyorsa, bunları çağrının CreateDefaultBuilder içinde bir IWebHostBuilder ve ConfigureServices yöntemini kullanarak yapılandırabilirsiniz.

Başlangıç sınıfı, denetleyicilerden ara yazılıma, Filtreler'den kendi Hizmetlerinize kadar ASP.NET Core uygulamanızın diğer bölümlerini nasıl yapılandırabileceğinize yönelik bir modeldir. Her durumda, Açık Bağımlılıklar İlkesi'ni izlemeniz, doğrudan oluşturmak yerine bağımlılıklarınızı istemeniz ve uygulamanızın tamamında bağımlılık eklemeden yararlanmanız gerekir. Uygulamaları, özellikle altyapıyla çalışan veya yan etkileri olan hizmetleri ve nesneleri doğrudan nerede ve nasıl örneklediğinize dikkat edin. Uygulama çekirdeğinizde tanımlanan ve belirli uygulama türlerine yönelik sabit kodlama başvurularına bağımsız değişken olarak geçirilen soyutlamalarla çalışmayı tercih edin.

Uygulamayı yapılandırma

Monolitik uygulamaların genellikle tek bir giriş noktası vardır. ASP.NET Core web uygulaması söz konusu olduğunda, giriş noktası ASP.NET Core web projesi olacaktır. Ancak bu, çözümün tek bir projeden oluşması gerektiği anlamına gelmez. Endişelerin ayrımını takip etmek için uygulamayı farklı katmanlara ayırmak yararlı olur. Katmanlara ayrıldığında, klasörlerin ötesine geçerek projeleri ayırmak daha iyi kapsülleme elde etmeye yardımcı olabilir. ASP.NET Core uygulamasıyla bu hedeflere ulaşmak için en iyi yaklaşım, 5. bölümde ele alınan Temiz Mimari'nin bir varyasyonudur. Bu yaklaşımın ardından uygulamanın çözümü kullanıcı arabirimi, Altyapı ve ApplicationCore için ayrı kitaplıklar oluşturur.

Bu projelere ek olarak, ayrı test projeleri de dahil edilir (Test, Bölüm 9'da ele alınıyor).

Uygulamanın nesne modeli ve arabirimleri ApplicationCore projesine yerleştirilmelidir. Bu projenin mümkün olduğunca az bağımlılığı olacaktır (ve belirli altyapıyla ilgili hiçbir sorun yoktur) ve çözümdeki diğer projeler buna başvuracaktır. Kalıcı olması gereken iş varlıkları, altyapıya doğrudan bağımlı olmayan hizmetler gibi ApplicationCore projesinde tanımlanır.

Kalıcılığın nasıl gerçekleştirileceği veya bir kullanıcıya bildirimlerin nasıl gönderilebileceği gibi uygulama ayrıntıları Altyapı projesinde tutulur. Bu proje Entity Framework Core gibi uygulamaya özgü paketlere başvurur, ancak bu uygulamalarla ilgili ayrıntıları projenin dışında sunmamalıdır. Altyapı hizmetleri ve depoları ApplicationCore projesinde tanımlanan arabirimleri uygulamalıdır ve kalıcılık uygulamaları ApplicationCore'da tanımlanan varlıkları almak ve depolamaktan sorumludur.

ASP.NET Core kullanıcı arabirimi projesi kullanıcı arabirimi düzeyindeki tüm endişelerden sorumludur, ancak iş mantığı veya altyapı ayrıntılarını içermemelidir. Aslında, ideal olarak altyapı projesine bağımlılığı bile olmamalıdır. Bu, iki proje arasındaki bağımlılığın yanlışlıkla kullanılmadığından emin olmanıza yardımcı olur. Bu, her projedeki Modül sınıflarında DI kuralları tanımlamanıza olanak tanıyan Autofac gibi bir üçüncü taraf DI kapsayıcısı kullanılarak elde edilebilir.

Uygulamayı uygulama ayrıntılarından ayırmaya yönelik bir diğer yaklaşım da, uygulamanın mikro hizmetleri çağırmasını sağlamak ve belki de tek tek Docker kapsayıcılarında dağıtılmış olmasıdır. Bu, iki proje arasında DI'den yararlanmaya kıyasla endişelerin ve ayırmanın daha da fazla ayrımını sağlar, ancak daha karmaşıktır.

Özellik düzenleme

Varsayılan olarak, ASP.NET Core uygulamaları klasör yapılarını Denetleyiciler ve Görünümler ile sık sık ViewModel'leri içerecek şekilde düzenler. Bu sunucu tarafı yapılarını desteklemek için istemci tarafı kodu genellikle wwwroot klasöründe ayrı olarak depolanır. Ancak, belirli bir özellik üzerinde çalışmak genellikle bu klasörler arasında atlama gerektirdiğinden, büyük uygulamalar bu kuruluşla ilgili sorunlarla karşılaşabilir. Her klasördeki dosya ve alt klasör sayısı arttıkça bu durum giderek daha da zorlaşır ve bu da Çözüm Gezgini arasında çok fazla kaydırmaya neden olur. Bu sorunun bir çözümü, uygulama kodunu dosya türü yerine özelliğe göre düzenlemektir. Bu kuruluş stili genellikle özellik klasörleri veya özellik dilimleri olarak adlandırılır (ayrıca bkz: Dikey Dilimler).

ASP.NET Core MVC bu amaçla Alanları destekler. Alanları kullanarak, her Alan klasöründe ayrı Denetleyiciler ve Görünümler klasörleri (ve ilişkili modeller) oluşturabilirsiniz. Şekil 7-1'de Alanlar kullanılarak örnek bir klasör yapısı gösterilmektedir.

Örnek Alan Kuruluşu

Şekil 7-1. Örnek Alan Kuruluşu

Alanlar'ı kullanırken, denetleyicilerinizi ait oldukları alanın adıyla süslemek için öznitelikleri kullanmanız gerekir:

[Area("Catalog")]
public class HomeController
{}

Rotalarınıza alan desteği de eklemeniz gerekir:

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(name: "areaRoute", pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
    endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
});

Alanlar için yerleşik desteğe ek olarak, öznitelikler ve özel yollar yerine kendi klasör yapınızı ve kuralları da kullanabilirsiniz. Bu, Görünümler, Denetleyiciler vb. için ayrı klasörler içermeyen özellik klasörlerine sahip olmanıza olanak tanır, hiyerarşiyi daha iyi tutar ve her özellik için tüm ilgili dosyaları tek bir yerde görmeyi kolaylaştırır. API'ler için klasörler denetleyicileri değiştirmek için kullanılabilir ve her klasör tüm API Uç Noktalarını ve bunların ilişkili DTO'larını içerebilir.

ASP.NET Core, davranışını denetlemek için yerleşik kural türlerini kullanır. Bu kuralları değiştirebilir veya değiştirebilirsiniz. Örneğin, belirli bir denetleyicinin ad alanına göre (genellikle denetleyicinin bulunduğu klasörle bağıntılı olan) özellik adını otomatik olarak alacak bir kural oluşturabilirsiniz:

public class FeatureConvention : IControllerModelConvention
{
    public void Apply(ControllerModel controller)
    {
        controller.Properties.Add("feature",
        GetFeatureName(controller.ControllerType));
    }

    private string GetFeatureName(TypeInfo controllerType)
    {
        string[] tokens = controllerType.FullName.Split('.');
        if (!tokens.Any(t => t == "Features")) return "";
        string featureName = tokens
            .SkipWhile(t => !t.Equals("features", StringComparison.CurrentCultureIgnoreCase))
            .Skip(1)
            .Take(1)
            .FirstOrDefault();
        return featureName;
    }
}

Daha sonra uygulamanıza ConfigureServices (veya Program.cs) içinde MVC desteği eklediğinizde bu kuralı bir seçenek olarak belirtirsiniz:

// ConfigureServices
services.AddMvc(o => o.Conventions.Add(new FeatureConvention()));

// Program.cs
builder.Services.AddMvc(o => o.Conventions.Add(new FeatureConvention()));

ASP.NET Core MVC ayrıca görünümleri bulmak için bir kural kullanır. Görünümlerin özellik klasörlerinizde bulunması için bunu özel bir kuralla geçersiz kılabilirsiniz (yukarıdaki FeatureConvention tarafından sağlanan özellik adını kullanarak). Bu yaklaşım hakkında daha fazla bilgi edinebilir ve msdn dergisinin ASP.NET Core MVC için Özellik Dilimleri makalesinden bir çalışma örneği indirebilirsiniz.

API'ler ve Blazor uygulamalar

Uygulamanız güvenliği sağlanması gereken bir dizi web API'sine sahipse, bu API'ler ideal olarak Görünüm veya Razor Sayfaları uygulamanızdan ayrı bir proje olarak yapılandırılmalıdır. API'leri, özellikle de genel API'leri sunucu tarafı web uygulamanızdan ayırmanın bir dizi avantajı vardır. Bu uygulamalar genellikle benzersiz dağıtım ve yük özelliklerine sahip olur. Ayrıca, tanımlama bilgisi tabanlı kimlik doğrulaması ve API'lerden yararlanan standart form tabanlı uygulamalarla büyük olasılıkla belirteç tabanlı kimlik doğrulaması kullanan farklı güvenlik mekanizmalarını benimseme olasılıkları da yüksektir.

Ayrıca, Blazor ister Sunucu ister BlazorWebAssemblykullansın Blazor uygulamalar ayrı projeler olarak oluşturulmalıdır. Uygulamalar, güvenlik modellerinin yanı sıra farklı çalışma zamanı özelliklerine sahiptir. Ortak türleri sunucu tarafı web uygulamasıyla (veya API projesiyle) paylaşma olasılığı yüksektir ve bu türler ortak bir paylaşılan projede tanımlanmalıdır.

eShopOnWeb'e yönetici BlazorWebAssembly arabirimi eklenmesi için birkaç yeni proje eklenmesi gerekiyordu. Projenin BlazorWebAssembly kendisi, BlazorAdmin. Tarafından BlazorAdmin kullanılan ve belirteç tabanlı kimlik doğrulamasını kullanacak şekilde yapılandırılan yeni bir genel API uç noktası kümesi projede PublicApi tanımlanır. Ayrıca bu projelerin her ikisi tarafından kullanılan bazı paylaşılan türler yeni BlazorShared bir projede tutulur.

Hem hem de PublicApiBlazorAdmin? için gerekli olan türleri paylaşmak için kullanılabilecek ortak ApplicationCore bir proje varken neden ayrı BlazorShared bir proje ekleyebileceğiniz sorulabilir. Bunun yanıtı, bu projenin uygulamanın tüm iş mantığını içermesi ve bu nedenle gerekliden çok daha büyük olması ve ayrıca sunucuda güvenli tutulması gerekmesi olasılığının çok daha yüksek olmasıdır. tarafından BlazorAdmin başvuruda bulunulan tüm kitaplıkların, uygulamayı yüklediklerinde Blazor kullanıcıların tarayıcılarına indirileceğini unutmayın.

Ön Uçlar için Arka Uçlar (BFF) desenini kullanıp kullanmadığına bağlı olarak, uygulama tarafından BlazorWebAssembly kullanılan API'ler türlerini %100 ile Blazorpaylaşamayabilir. Özellikle, birçok farklı istemci tarafından tüketilmesi amaçlanan bir genel API, istemciye özgü paylaşılan bir projede paylaşmak yerine kendi isteği ve sonuç türlerini tanımlayabilir. eShopOnWeb örneğinde, projenin aslında bir genel API'yi barındırdığı, bu nedenle tüm istek ve yanıt türlerinin projeden gelmediği varsayımı BlazorShared yapılmaktadırPublicApi.

Geniş kapsamlı kritik konular

Uygulamalar büyüdükçe, yinelemeyi ortadan kaldırmak ve tutarlılığı korumak için çapraz kesme endişelerini dikkate almak giderek daha önemli hale gelir. ASP.NET Core uygulamalarında çapraz kesme endişelerine örnek olarak kimlik doğrulaması, model doğrulama kuralları, çıkış önbelleğe alma ve hata işleme verilebilir. ASP.NET Core MVC filtreleri , istek işleme işlem hattındaki belirli adımlarda önce veya sonra kod çalıştırmanıza olanak sağlar. Örneğin, bir filtre model bağlamadan önce ve sonra, bir eylemden önce ve sonra ya da bir eylemin sonucundan önce ve sonra çalıştırılabilir. İşlem hattının geri kalanına erişimi denetlemek için yetkilendirme filtresi de kullanabilirsiniz. Şekil 7-2, yapılandırılmışsa istek yürütmenin filtreler aracılığıyla nasıl aktığını gösterir.

İstek Yetkilendirme Filtreleri, Kaynak Filtreleri, Model Bağlama, Eylem Filtreleri, Eylem Yürütme ve Eylem Sonucu Dönüştürme, Özel Durum Filtreleri, Sonuç Filtreleri ve Sonuç Yürütme aracılığıyla işlenir. Çıkışta istek, istemciye gönderilen bir yanıt haline gelmeden önce yalnızca Sonuç Filtreleri ve Kaynak Filtreleri tarafından işlenir.

Şekil 7-2. Filtreler ve istek işlem hattı aracılığıyla yürütme isteğinde bulunabilirsiniz.

Filtreler genellikle öznitelik olarak uygulandığı için bunları denetleyicilere veya eylemlere (hatta genel olarak) uygulayabilirsiniz. Bu şekilde eklendiğinde, eylem düzeyinde belirtilen filtreler, denetleyici düzeyinde belirtilen filtreleri geçersiz kılar veya bunlar genel filtreleri geçersiz kılar. Örneğin, [Route] öznitelik denetleyiciler ve eylemler arasında yollar oluşturmak için kullanılabilir. Benzer şekilde, yetkilendirme denetleyici düzeyinde yapılandırılabilir ve ardından aşağıdaki örnekte gösterildiği gibi tek tek eylemler tarafından geçersiz kılınabilir:

[Authorize]
public class AccountController : Controller
{
    [AllowAnonymous] // overrides the Authorize attribute
    public async Task<IActionResult> Login() {}
    public async Task<IActionResult> ForgotPassword() {}
}

İlk yöntem olan Login, denetleyici düzeyinde yetkilendirme filtresi kümesini geçersiz kılmak için filtreyi (özniteliği) kullanır [AllowAnonymous] . Eylem ForgotPassword (ve sınıfta AllowAnonymous özniteliği olmayan diğer tüm eylemler) kimliği doğrulanmış bir istek gerektirir.

Filtreler, API'ler için yaygın hata işleme ilkeleri biçiminde yinelenenleri ortadan kaldırmak için kullanılabilir. Örneğin, tipik bir API ilkesi, var olmayan anahtarlara başvuran isteklere NotFound yanıtı ve model doğrulaması başarısız olursa bir BadRequest yanıt döndürmektir. Aşağıdaki örnekte, bu iki ilkenin çalışması gösterilmektedir:

[HttpPut("{id}")]
public async Task<IActionResult> Put(int id, [FromBody]Author author)
{
    if ((await _authorRepository.ListAsync()).All(a => a.Id != id))
    {
        return NotFound(id);
    }
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }
    author.Id = id;
    await _authorRepository.UpdateAsync(author);
    return Ok();
}

Eylem yöntemlerinizin bunun gibi koşullu kodlarla karmaşık hale gelmesine izin verme. Bunun yerine, ilkeleri gerektiği gibi uygulanabilecek filtrelere çekin. Bu örnekte, API'ye her komut gönderildiğinde gerçekleşmesi gereken model doğrulama denetimi aşağıdaki öznitelikle değiştirilebilir:

public class ValidateModelAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (!context.ModelState.IsValid)
        {
            context.Result = new BadRequestObjectResult(context.ModelState);
        }
    }
}

Ardalis.ValidateModel paketini ekleyerek projenize NuGet bağımlılığı olarak ekleyebilirsinizValidateModelAttribute. API'ler için, ayrı ValidateModel bir filtreye gerek kalmadan bu davranışı zorlamak için özniteliğini kullanabilirsinizApiController.

Benzer şekilde, bir kaydın var olup olmadığını denetlemek ve eylem yürütülmeden önce 404 döndürmek için bir filtre kullanılabilir ve bu da eylemde bu denetimleri gerçekleştirme gereksinimini ortadan kaldırır. Yaygın kuralları kaldırıp altyapı kodunu ve iş mantığını kullanıcı arabiriminizden ayırmak için çözümünüzü düzenledikten sonra, MVC eylem yöntemleriniz son derece ince olmalıdır:

[HttpPut("{id}")]
[ValidateAuthorExists]
public async Task<IActionResult> Put(int id, [FromBody]Author author)
{
    await _authorRepository.UpdateAsync(author);
    return Ok();
}

Gerçek Dünya ASP.NET Core MVC Filtreleri adlı MSDN Dergisi makalesinden filtre uygulama hakkında daha fazla bilgi edinebilir ve çalışma örneğini indirebilirsiniz.

Doğrulama hataları (Hatalı İstek), kaynak bulunamadı ve sunucu hataları gibi yaygın senaryolara dayalı olarak API'lerden bir dizi ortak yanıtınız olduğunu fark ederseniz, bir sonuç soyutlaması kullanmayı düşünebilirsiniz. Sonuç soyutlaması API uç noktaları tarafından kullanılan hizmetler tarafından döndürülür ve denetleyici eylemi veya uç noktası bunları içine IActionResultsçevirmek için bir filtre kullanır.

Başvurular – Uygulamaları yapılandırma

Güvenlik

Web uygulamalarının güvenliğini sağlamak, dikkat edilmesi gereken birçok konu başlığıdır. En temel düzeyde güvenlik, belirli bir isteğin kimden geldiğini bildiğinizden emin olmak ve ardından isteğin yalnızca olması gereken kaynaklara erişimi olduğundan emin olmaktır. Kimlik doğrulaması, istekle birlikte sağlanan kimlik bilgilerini güvenilen bir veri deposundakilerle karşılaştırarak isteğin bilinen bir varlıktan geliyor olarak kabul edilmesi gerekip gerekmediğini görme işlemidir. Yetkilendirme, kullanıcı kimliğine göre belirli kaynaklara erişimi kısıtlama işlemidir. Üçüncü bir güvenlik sorunu, isteklerin üçüncü taraflar tarafından gizlice dinlemeye karşı korunmasıdır ve en azından ssl'nin uygulamanız tarafından kullanıldığından emin olmanız gerekir.

Kimlik

ASP.NET Core Identity, uygulamanız için oturum açma işlevselliğini desteklemek için kullanabileceğiniz bir üyelik sistemidir. Yerel kullanıcı hesaplarının yanı sıra Microsoft Hesabı, Twitter, Facebook, Google ve daha fazlası gibi sağlayıcılardan dış oturum açma sağlayıcısı desteğine sahiptir. Uygulamanız, ASP.NET Çekirdek Kimlik'e ek olarak Windows kimlik doğrulamasını veya Kimlik Sunucusu gibi bir üçüncü taraf kimlik sağlayıcısını da kullanabilir.

ASP.NET Çekirdek Kimliği, Bireysel Kullanıcı Hesapları seçeneği belirlenmişse yeni proje şablonlarına eklenir. Bu şablon kayıt, oturum açma, dış oturum açma işlemleri, unutulan parolalar ve ek işlevler için destek içerir.

Kimliğin önceden yapılandırılmış olması için Tek Tek Kullanıcı Hesapları'nı seçin

Şekil 7-3. Kimliğin önceden yapılandırılmış olması için Bireysel Kullanıcı Hesapları'nı seçin.

Kimlik desteği Program.cs veya Startupiçinde yapılandırılır ve ara yazılımların yanı sıra hizmetleri yapılandırmayı da içerir.

Program.cs'da Kimliği Yapılandırma

Program.cs,örnektekiWebHostBuilder hizmetleri yapılandıracaksınız ve uygulama oluşturulduktan sonra ara yazılımını yapılandıracaksınız. Dikkate alınması gereken önemli noktalar, gerekli hizmetler için AddDefaultIdentity çağrısı ve UseAuthentication gerekli ara yazılımı ekleyen ve UseAuthorization çağrılarıdır.

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
  app.UseExceptionHandler("/Error");
  // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
  app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapRazorPages();

app.Run();

Uygulama başlatmada Kimlik yapılandırma

// Add framework services.
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();
builder.Services.AddMvc();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapRazorPages();

ve öncesinde MapRazorPagesgörünmesi önemlidir.UseAuthenticationUseAuthorization Kimlik hizmetlerini yapılandırırken çağrısı olduğunu fark AddDefaultTokenProvidersedeceksiniz. Bunun web iletişimlerinin güvenliğini sağlamak için kullanılabilecek belirteçlerle hiçbir ilgisi yoktur, ancak bunun yerine, kimliklerini onaylamaları için kullanıcılara SMS veya e-posta yoluyla gönderilebilen istemler oluşturan sağlayıcıları ifade eder.

resmi ASP.NET Core belgelerinden iki öğeli kimlik doğrulamasını yapılandırma ve dış oturum açma sağlayıcılarını etkinleştirme hakkında daha fazla bilgi edinebilirsiniz.

Kimlik Doğrulaması

Kimlik doğrulaması, sisteme kimin eriştiğini belirleme işlemidir. ASP.NET Çekirdek Kimliği ve önceki bölümde gösterilen yapılandırma yöntemlerini kullanıyorsanız, uygulamadaki bazı kimlik doğrulama varsayılanları otomatik olarak yapılandırılır. Ancak, bu varsayılanları el ile yapılandırabilir veya AddIdentity tarafından ayarlananları geçersiz kılabilirsiniz. Identity kullanıyorsanız tanımlama bilgisi tabanlı kimlik doğrulamasını varsayılan düzen olarak yapılandırıyor.

Web tabanlı kimlik doğrulamasında genellikle bir sistemin istemcisinin kimliğini doğrulama işlemi boyunca gerçekleştirilebilecek en fazla beş eylem vardır. Bu ifadeler şunlardır:

  • Kimlik doğrulaması. İstemci tarafından sağlanan bilgileri kullanarak uygulama içinde kullanacağı bir kimlik oluşturun.
  • Meydan okuma. Bu eylem, istemcinin kendisini tanımlamasını istemek için kullanılır.
  • Koru -sun. İstemciye eylem gerçekleştirmelerinin yasak olduğunu bildirin.
  • Oturum açın. Mevcut istemciyi bir şekilde kalıcı hale getir.
  • Oturum kapatma. İstemciyi kalıcılığından kaldırın.

Web uygulamalarında kimlik doğrulaması gerçekleştirmek için bir dizi yaygın teknik vardır. Bunlar düzen olarak adlandırılır. Belirli bir düzen, yukarıdaki seçeneklerin bazıları veya tümü için eylemleri tanımlar. Bazı düzenler yalnızca eylemlerin bir alt kümesini destekler ve desteklemediği işlemleri gerçekleştirmek için ayrı bir düzen gerektirebilir. Örneğin, OpenId-Bağlan (OIDC) düzeni Oturum Açmayı veya Oturumu Kapatma'yı desteklemez, ancak genellikle bu kalıcılık için Tanımlama Bilgisi kimlik doğrulamasını kullanacak şekilde yapılandırılır.

ASP.NET Core uygulamanızda, yukarıda açıklanan eylemlerin her biri için isteğe bağlı belirli düzenlerin yanı sıra bir DefaultAuthenticateScheme de yapılandırabilirsiniz. Örneğin, DefaultChallengeScheme ve DefaultForbidScheme. Çağırma AddIdentity , uygulamanın çeşitli yönlerini yapılandırarak birçok gerekli hizmet ekler. Ayrıca, kimlik doğrulama düzenini yapılandırmak için şu çağrıyı içerir:

builder.Services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
    options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
    options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
});

Bu şemalar, kalıcılık ve kimlik doğrulaması için oturum açma sayfalarına yönlendirme için tanımlama bilgilerini varsayılan olarak kullanır. Bu düzenler, web tarayıcıları aracılığıyla kullanıcılarla etkileşim kuran web uygulamaları için uygundur, ancak API'ler için önerilmez. Bunun yerine API'ler genellikle JWT taşıyıcı belirteçleri gibi başka bir kimlik doğrulama biçimi kullanır.

Web API'leri, .NET uygulamalarında ve diğer çerçevelerdeki eşdeğer türlerde olduğu gibi HttpClient kodlar tarafından kullanılır. Bu istemciler bir API çağrısından veya sorun oluştuğunu belirten bir durum kodundan kullanılabilir bir yanıt bekler. Bu istemciler bir tarayıcı üzerinden etkileşim kurmuyor ve API'nin döndürebileceği herhangi bir HTML'yi işlemez veya bunlarla etkileşim kurmaz. Bu nedenle, API uç noktalarının kimlik doğrulaması yapılmazsa istemcilerini oturum açma sayfalarına yönlendirmesi uygun değildir. Başka bir şema daha uygundur.

API'ler için kimlik doğrulamasını yapılandırmak için, eShopOnWeb başvuru uygulamasında proje tarafından kullanılan kimlik doğrulamasını PublicApi aşağıdaki gibi ayarlayabilirsiniz:

builder.Services
    .AddAuthentication(config =>
    {
      config.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    .AddJwtBearer(config =>
    {
        config.RequireHttpsMetadata = false;
        config.SaveToken = true;
        config.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(key),
            ValidateIssuer = false,
            ValidateAudience = false
        };
    });

Tek bir proje içinde birden çok farklı kimlik doğrulama düzeni yapılandırmak mümkün olsa da, tek bir varsayılan düzen yapılandırmak çok daha kolaydır. Bu nedenle, diğerlerinin yanı sıra, eShopOnWeb başvuru uygulaması API'lerini uygulamanın görünümlerini ve Razor Sayfalarını içeren ana Web projeden ayrı olarak kendi projesine PublicApiayırır.

Blazor Uygulamalarda kimlik doğrulaması

Blazor Sunucu uygulamaları, diğer ASP.NET Core uygulamalarıyla aynı kimlik doğrulama özelliklerinden yararlanabilir. BlazorWebAssembly uygulamalar yerleşik Kimlik ve Kimlik Doğrulama sağlayıcılarını kullanamaz, ancak bunlar tarayıcıda çalıştırıldığından. BlazorWebAssembly uygulamalar, kullanıcı kimlik doğrulama durumunu yerel olarak depolayabilir ve kullanıcıların gerçekleştirebilmesi gereken eylemleri belirlemek için taleplere erişebilir. Ancak, kullanıcılar uygulamayı kolayca atlayıp API'lerle doğrudan etkileşime geçebildiğinden, uygulama içinde BlazorWebAssembly uygulanan herhangi bir mantık ne olursa olsun tüm kimlik doğrulama ve yetkilendirme denetimleri sunucuda gerçekleştirilmelidir.

Başvurular – Kimlik Doğrulaması

Yetkilendirme

En basit yetkilendirme biçimi, anonim kullanıcılara erişimi kısıtlamayı içerir. Bu işlev, özniteliği belirli denetleyicilere veya eylemlere [Authorize] uygulanarak elde edilebilir. Roller kullanılıyorsa öznitelik, aşağıdaki gibi belirli rollere ait kullanıcılara erişimi kısıtlamak için daha fazla genişletilebilir:

[Authorize(Roles = "HRManager,Finance")]
public class SalaryController : Controller
{

}

Bu durumda, veya Finance rollerine (veya her ikisineHRManager) ait kullanıcıların SalaryController'a erişimi olur. Bir kullanıcının birden çok role (birkaç rolden birine değil) ait olmasını zorunlu kılması için, özniteliğini her seferinde gerekli bir rol belirterek birden çok kez uygulayabilirsiniz.

Birçok farklı denetleyicide ve eylemde belirli rol kümelerinin dize olarak belirtilmesi istenmeyen tekrarlara yol açabilir. En azından, bu dize değişmez değerleri için sabitleri tanımlayın ve dizeyi belirtmeniz gereken her yerde sabitleri kullanın. Ayrıca yetkilendirme kurallarını kapsülleyen yetkilendirme ilkelerini yapılandırabilir ve ardından özniteliği uygularken tek tek roller yerine ilkeyi [Authorize] belirtebilirsiniz:

[Authorize(Policy = "CanViewPrivateReport")]
public IActionResult ExecutiveSalaryReport()
{
    return View();
}

İlkeleri bu şekilde kullanarak, kısıtlanan eylem türlerini buna uygulanan belirli rollerden veya kurallardan ayırabilirsiniz. Daha sonra, belirli kaynaklara erişmesi gereken yeni bir rol oluşturursanız, her [Authorize] öznitelikte her rol listesini güncelleştirmek yerine yalnızca bir ilkeyi güncelleştirebilirsiniz.

Talepler

Talepler, kimliği doğrulanmış bir kullanıcının özelliklerini temsil eden ad değer çiftleridir. Örneğin, kullanıcıların çalışan numarasını talep olarak depolayabilirsiniz. Daha sonra talepler yetkilendirme ilkelerinin bir parçası olarak kullanılabilir. Bu örnekte gösterildiği gibi adlı bir talebin varlığını gerektiren "EmployeeOnly" adlı "EmployeeNumber"bir ilke oluşturabilirsiniz:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddAuthorization(options =>
    {
        options.AddPolicy("EmployeeOnly", policy => policy.RequireClaim("EmployeeNumber"));
    });
}

Bu ilke daha sonra yukarıda açıklandığı gibi herhangi bir denetleyiciyi [Authorize] ve/veya eylemi korumak için özniteliğiyle birlikte kullanılabilir.

Web API'lerinin güvenliğini sağlama

Çoğu web API'sinde belirteç tabanlı kimlik doğrulama sistemi uygulanmalıdır. Belirteç kimlik doğrulaması durum bilgisi yoktur ve ölçeklenebilir olacak şekilde tasarlanmıştır. Belirteç tabanlı kimlik doğrulama sisteminde, istemcinin önce kimlik doğrulama sağlayıcısıyla kimlik doğrulaması yapması gerekir. Başarılı olursa, istemciye yalnızca şifreleme açısından anlamlı bir karakter dizesi olan bir belirteç verilir. Belirteçler için en yaygın biçim JSON Web Belirteci veya JWT'dir (genellikle "jot" olarak okunur). daha sonra istemcinin bir API'ye istek göndermesi gerektiğinde, bu belirteci isteğe üst bilgi olarak ekler. Ardından sunucu, isteği tamamlamadan önce istek üst bilgisinde bulunan belirteci doğrular. Şekil 7-4'de bu işlem gösterilmektedir.

TokenAuth

Şekil 7-4. Web API'leri için belirteç tabanlı kimlik doğrulaması.

Kendi kimlik doğrulama hizmetinizi oluşturabilir, Azure AD ve OAuth ile tümleştirebilir veya IdentityServer gibi bir açık kaynak aracı kullanarak bir hizmet uygulayabilirsiniz.

JWT belirteçleri, kullanıcı hakkındaki talepleri ekleyebilir ve bu talepler istemcide veya sunucuda okunabilir. JWT belirtecinin içeriğini görüntülemek için jwt.io gibi bir araç kullanabilirsiniz. parolalar veya anahtarlar gibi hassas verileri JTW belirteçlerinde depolamayın çünkü içerikleri kolayca okunur.

SPA veya BlazorWebAssembly uygulamalarla JWT belirteçlerini kullanırken, belirteci istemcide bir yerde depolamanız ve ardından her API çağrısına eklemeniz gerekir. Bu etkinlik genellikle aşağıdaki kodda gösterildiği gibi üst bilgi olarak yapılır:

// AuthService.cs in BlazorAdmin project of eShopOnWeb
private async Task SetAuthorizationHeader()
{
      var token = await GetToken();
      _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
}

Yukarıdaki yöntemi çağırdıktan sonra, ile _httpClient yapılan isteklerde belirtecin isteğin üst bilgilerine ekli olması, sunucu tarafı API'sinin isteğin kimliğini doğrulamasına ve yetkilendirmesine olanak sağlar.

Özel Güvenlik

Dikkat

Genel bir kural olarak, kendi özel güvenlik uygulamalarınızı uygulamaktan kaçının.

Şifreleme, kullanıcı üyeliği veya belirteç oluşturma sisteminin "kendi uygulamanızın sıralanması" konusunda özellikle dikkatli olun. Neredeyse kesinlikle özel bir uygulamadan daha iyi bir güvenliğe sahip olacak birçok ticari ve açık kaynak alternatif vardır.

Başvurular – Güvenlik

İstemci iletişimi

Web API'leri aracılığıyla sayfa sunmanın ve veri isteklerine yanıt vermenin yanı sıra, ASP.NET Core uygulamaları bağlı istemcilerle doğrudan iletişim kurabilir. Bu giden iletişim, en yaygın olanı WebSockets olan çeşitli aktarım teknolojilerini kullanabilir. ASP.NET Core SignalR, uygulamalarınıza gerçek zamanlı sunucudan istemciye iletişim işlevselliği eklemeyi kolaylaştıran bir kitaplıktır. SignalR, WebSockets dahil olmak üzere çeşitli aktarım teknolojilerini destekler ve geliştiricinin uygulama ayrıntılarının çoğunu soyutlar.

WebSockets'in doğrudan veya diğer tekniklerin kullanılması farketmeksizin gerçek zamanlı istemci iletişimi, çeşitli uygulama senaryolarında yararlıdır. Bazı Örnekler:

  • Canlı sohbet odası uygulamaları

  • Uygulamaları izleme

  • İş ilerleme durumu güncelleştirmeleri

  • Notifications

  • Etkileşimli form uygulamaları

Uygulamalarınıza istemci iletişimi oluştururken genellikle iki bileşen vardır:

  • Sunucu tarafı bağlantı yöneticisi (SignalR Hub, WebSocketManager WebSocketHandler)

  • İstemci tarafı kitaplığı

İstemciler tarayıcılarla sınırlı değildir; mobil uygulamalar, konsol uygulamaları ve diğer yerel uygulamalar da SignalR/WebSockets kullanarak iletişim kurabilir. Aşağıdaki basit program, WebSocketManager örnek uygulamasının parçası olarak konsola bir sohbet uygulamasına gönderilen tüm içeriği yankılar:

public class Program
{
    private static Connection _connection;
    public static void Main(string[] args)
    {
        StartConnectionAsync();
        _connection.On("receiveMessage", (arguments) =>
        {
            Console.WriteLine($"{arguments[0]} said: {arguments[1]}");
        });
        Console.ReadLine();
        StopConnectionAsync();
    }

    public static async Task StartConnectionAsync()
    {
        _connection = new Connection();
        await _connection.StartConnectionAsync("ws://localhost:65110/chat");
    }

    public static async Task StopConnectionAsync()
    {
        await _connection.StopConnectionAsync();
    }
}

Uygulamalarınızın istemci uygulamalarıyla doğrudan iletişim kurma yollarını ve gerçek zamanlı iletişimin uygulamanızın kullanıcı deneyimini geliştirip geliştirmeyeceğini göz önünde bulundurun.

Başvurular – İstemci İletişimi

Etki alanı odaklı tasarım – Bunu uygulamanız gerekir mi?

Etki Alanı Odaklı Tasarım (DDD), iş etki alanına odaklanmayı vurgulayan bir yazılım oluşturmaya yönelik çevik bir yaklaşımdır. Geliştiricilerle gerçek dünya sisteminin nasıl çalıştığıyla ilgili olabilecek iş alanı uzmanlarıyla iletişim ve etkileşime büyük önem verir. Örneğin, hisse senetlerini işleyen bir sistem oluşturuyorsanız, etki alanı uzmanınız deneyimli bir hisse senedi aracısı olabilir. DDD, büyük ve karmaşık iş sorunlarını ele almak için tasarlanmıştır ve etki alanını anlama ve modellemeye yapılan yatırım buna değmediği için genellikle daha küçük, daha basit uygulamalar için uygun değildir.

DDD yaklaşımını izleyerek yazılım oluştururken ekibinizin (teknik olmayan paydaşlar ve katkıda bulunanlar dahil) sorun alanı için yaygın bir dil geliştirmesi gerekir. Yani, modellenen gerçek dünya kavramı, yazılım eşdeğeri ve kavramı kalıcı hale getirmek için mevcut olabilecek tüm yapılar (örneğin, veritabanı tabloları) için aynı terminoloji kullanılmalıdır. Bu nedenle, yaygın dilde açıklanan kavramlar etki alanı modelinizin temelini oluşturmalıdır.

Etki alanı modeliniz, sistemin davranışını göstermek için birbiriyle etkileşim kuran nesnelerden oluşur. Bu nesneler aşağıdaki kategorilere düşebilir:

DDD etki alanı modeli, model içindeki karmaşık davranışı kapsüllemelidir. Varlıklar, özellikle de yalnızca özellik koleksiyonları olmamalıdır. Etki alanı modelinin davranışı olmadığında ve yalnızca sistemin durumunu temsil ettiğinde, DDD'de istenmeyen bir anemik model olduğu söylenir.

Bu model türlerine ek olarak, DDD genellikle çeşitli desenler kullanır:

DDD ayrıca daha önce tartışılan Temiz Mimari'nin kullanılmasını önererek birim testleri kullanılarak kolayca doğrulanabilen gevşek bağlama, kapsülleme ve koda olanak tanır.

Ne zaman DDD uygulamanız gerekir?

DDD, önemli iş (yalnızca teknik değil) karmaşıklığı olan büyük uygulamalar için de uygundur. Uygulama, etki alanı uzmanlarının bilgisine ihtiyaç duyar. Etki alanı modelinin kendisinde, veri depolarından çeşitli kayıtların geçerli durumunu depolamanın ve almanın ötesinde iş kurallarını ve etkileşimleri temsil eden önemli bir davranış olmalıdır.

Ne zaman DDD uygulamamalısınız?

DDD, yalnızca CRUD (oluşturma/okuma/güncelleştirme/silme) olan daha küçük uygulamalar veya uygulamalar için garanti edilmeyecek modelleme, mimari ve iletişim yatırımlarını içerir. DDD'yi izleyerek uygulamanıza yaklaşmayı seçerseniz ancak etki alanınızda davranış içermeyen bir anemik model olduğunu fark ederseniz yaklaşımınızı yeniden düşünmeniz gerekebilir. Uygulamanızın DDD'ye ihtiyacı olmayabilir veya veritabanınızda veya kullanıcı arabiriminizde değil, etki alanı modelinde iş mantığını kapsüllemek için uygulamanızı yeniden düzenleme konusunda yardıma ihtiyacınız olabilir.

Karma yaklaşım, DDD'yi yalnızca uygulamanın işlem alanları veya daha karmaşık alanları için kullanmaktır, ancak uygulamanın daha basit CRUD veya salt okunur bölümleri için kullanılamaz. Örneğin, bir raporu görüntülemek veya pano verilerini görselleştirmek için verileri sorgularken Toplama kısıtlamalarına ihtiyacınız yoktur. Bu tür gereksinimler için ayrı, daha basit bir okuma modeline sahip olmak son derece kabul edilebilir.

Başvurular – Etki Alanı Odaklı Tasarım

Dağıtım

ASP.NET Core uygulamanızın nerede barındırılacağına bakılmaksızın dağıtma işleminde birkaç adım vardır. İlk adım, CLI komutu kullanılarak yapabilen uygulamayı yayımlamaktır dotnet publish . Bu adım uygulamayı derler ve uygulamayı çalıştırmak için gereken tüm dosyaları belirlenmiş bir klasöre yerleştirir. Visual Studio'dan dağıtım yaptığınızda, bu adım sizin için otomatik olarak gerçekleştirilir. Yayımlama klasörü, uygulama ve bağımlılıkları için .exe ve .dll dosyaları içerir. Bağımsız bir uygulama da .NET çalışma zamanının bir sürümünü içerir. ASP.NET Core uygulamaları yapılandırma dosyalarını, statik istemci varlıklarını ve MVC görünümlerini de içerir.

ASP.NET Core uygulamaları, uygulama (veya sunucu) kilitlenmesi durumunda sunucu önyükleme ve yeniden başlatma sırasında başlatılması gereken konsol uygulamalarıdır. Bu işlemi otomatikleştirmek için bir işlem yöneticisi kullanılabilir. ASP.NET Core için en yaygın işlem yöneticileri Linux üzerinde Nginx ve Apache, Windows üzerinde IIS veya Windows Hizmeti'dir.

İşlem yöneticisine ek olarak, ASP.NET Core uygulamaları ters ara sunucu kullanabilir. Ters ara sunucu İnternet'ten HTTP istekleri alır ve bazı ön işlemelerden sonra bunları Kestrel'e iletir. Ters proxy sunucuları, uygulama için bir güvenlik katmanı sağlar. Kestrel aynı bağlantı noktasında birden çok uygulama barındırmayı da desteklemez, bu nedenle ana bilgisayar üst bilgileri gibi teknikler, aynı bağlantı noktası ve IP adresinde birden çok uygulama barındırmayı etkinleştirmek için onunla kullanılamaz.

Kestrel'i İnternet'e

Şekil 7-5. ASP.NET ters ara sunucunun arkasında Kestrel'de barındırılma

Ters proxy'nin yardımcı olabileceği bir diğer senaryo da SSL/HTTPS kullanarak birden çok uygulamanın güvenliğini sağlamaktır. Bu durumda, yalnızca ters ara sunucu SSL'nin yapılandırılmış olması gerekir. Ters ara sunucu ile Kestrel arasındaki iletişim, Şekil 7-6'da gösterildiği gibi HTTP üzerinden gerçekleşebilir.

ASP.NET HTTPS ile güvenli bir ters ara sunucunun arkasında barındırılan

Şekil 7-6. ASP.NET HTTPS ile güvenli bir ters ara sunucunun arkasında barındırılan

Giderek popüler hale gelen bir yaklaşım, ASP.NET Core uygulamanızı yerel olarak barındırabileceğiniz veya bulut tabanlı barındırma için Azure'a dağıtabileceğiniz bir Docker kapsayıcısında barındırmaktır. Docker kapsayıcısı, Kestrel üzerinde çalışan uygulama kodunuzu içerebilir ve yukarıda gösterildiği gibi ters proxy sunucusunun arkasına dağıtılır.

Uygulamanızı Azure'da barındıracaksanız, microsoft Azure Uygulaması lication Gateway'i ayrılmış bir sanal gereç olarak kullanarak çeşitli hizmetler sağlayabilirsiniz. Application Gateway, tek tek uygulamalar için ters ara sunucu olarak davranmanın yanı sıra aşağıdaki özellikleri de sunabilir:

  • HTTP yük dengeleme

  • SSL boşaltma (yalnızca SSL'yi İnternet'e)

  • Uçtan Uca SSL

  • Çok siteli yönlendirme (tek bir Application Gateway'de en fazla 20 siteyi birleştirme)

  • Web uygulaması güvenlik duvarı

  • Websocket desteği

  • Gelişmiş tanılama

10. Bölüm'de Azure dağıtım seçenekleri hakkında daha fazla bilgi edinin.

Başvurular – Dağıtım