ASP.NET Core içinde tek sayfalı uygulamalar oluşturmak için JavaScript hizmetlerini kullanın

Scott Ade ve fiyaz hasan tarafından

Tek sayfalı uygulama (SPA), kendi kendine ait zengin Kullanıcı deneyimi nedeniyle popüler bir Web uygulaması türüdür. Angular veya Reactgibi istemci tarafı SPA çerçevelerini veya kitaplıklarını, ASP.NET Core gibi sunucu tarafı çerçeveleri ile tümleştirme zor olabilir. Tümleştirme sürecinde uçuşmayı azaltmak için JavaScript Hizmetleri geliştirilmiştir. Farklı istemci ve sunucu teknoloji yığınları arasında sorunsuz işleme sunar.

Uyarı

bu makalede açıklanan özellikler ASP.NET Core 3,0 itibariyle kullanımdan kalkmıştır. Microsoft. aspnetcore. spaservices. Extensions NuGet paketinde daha basit bir SPA çerçeveleri tümleştirme mekanizması mevcuttur. Daha fazla bilgi için bkz. Microsoft. aspnetcore. spaservices ve Microsoft. AspNetCore. NodeServices üzerinde kullanımdan bulunan [Duyuru].

JavaScript Hizmetleri nedir?

JavaScript Hizmetleri, ASP.NET Core yönelik istemci tarafı teknolojilerinin bir koleksiyonudur. amacı, ASP.NET Core, geliştiricilerin, maça 'ları oluşturmak için tercih edilen sunucu tarafı platformu olarak konumlandırmaktır.

JavaScript hizmetleri iki ayrı NuGet paketten oluşur:

Bu paketler, aşağıdaki senaryolarda faydalıdır:

  • Sunucuda JavaScript çalıştırma
  • SPA çerçevesi veya kitaplığı kullanma
  • WebPack ile istemci tarafı varlıkları derleme

Bu makaledeki odağın çoğu, SpaServices paketi kullanılarak yerleştirilir.

Maça Hizmetleri nedir?

istenmeyen hizmetler ASP.NET Core, geliştiricilerin, maça 'ları oluşturmak için tercih edilen sunucu tarafı platformu olarak konumlandırmak üzere oluşturulmuştur. istenmeyen hizmetler ASP.NET Core ile maça geliştirmek için gerekli değildir ve geliştiricileri belirli bir istemci çerçevesinde kilitlemez.

SpaServices şu gibi yararlı bir altyapı sağlar:

Toplu olarak, bu altyapı bileşenleri hem geliştirme iş akışını hem de çalışma zamanı deneyimini geliştirir. Bileşenler tek tek benimsemiş olabilir.

Spaservice kullanımı için Önkoşullar

SpaServices ile çalışmak için aşağıdakileri yüklemelisiniz:

  • NPM ile Node.js (sürüm 6 veya üzeri)

    • Bu bileşenlerin yüklendiğini doğrulamak ve bulunabilir olması için komut satırından aşağıdakileri çalıştırın:

      node -v && npm -v
      
    • Bir Azure Web sitesine dağıtım yapıyorsanız, — sunucu ortamlarında yüklü ve kullanılabilirNode.js herhangi bir eylem gerekmez.

  • .NET Core SDK 2,0 veya üzeri

    • Visual Studio 2017 kullanarak Windows, SDK .net Core platformlar arası geliştirme iş yükü seçilerek yüklenir.
  • Microsoft. aspnetcore. spaservices NuGet paketi

Sunucu tarafı prerendering

Evrensel (isomorphic olarak da bilinir) uygulaması, hem sunucu hem de istemci üzerinde çalışan bir JavaScript uygulamasıdır. Angular, React ve diğer popüler çerçeveler, bu uygulama geliştirme stili için evrensel bir platform sağlar. Fikir, öncelikle sunucu üzerinde Node.js aracılığıyla çerçeve bileşenlerini işlemek ve ardından istemciye daha fazla yürütme devretmek.

spaservices tarafından sunulan ASP.NET Core etiket yardımcıları , sunucuda JavaScript işlevlerini çağırarak sunucu tarafı prerendering 'in uygulanmasını basitleştirir.

Sunucu tarafı prerendering önkoşulları

ASPNET-prerendering NPM paketini yükler:

npm i -S aspnet-prerendering

Sunucu tarafı prerendering yapılandırması

Etiket Yardımcıları, projenin _ViewImports. cshtml dosyasında ad alanı kaydı aracılığıyla bulunabilir hale getirilir:

@using SpaServicesSampleApp
@addTagHelper "*, Microsoft.AspNetCore.Mvc.TagHelpers"
@addTagHelper "*, Microsoft.AspNetCore.SpaServices"

Bu etiket yardımcıları, görünümün içindeki HTML benzeri bir söz dizimini kullanarak doğrudan alt düzey API 'lerle iletişim kurmanın karmaşık özelliklerini soyutlar Razor .

<app asp-prerender-module="ClientApp/dist/main-server">Loading...</app>

ASP-PreRender-Module etiketi Yardımcısı

asp-prerender-moduleYukarıdaki kod örneğinde kullanılan etiket Yardımcısı, sunucu üzerinde clientapp/dist/main-server.js ' ı Node.js aracılığıyla yürütür. Netlik için main-server.js dosyası, WebPack derleme sürecinde TypeScript-to-JavaScript transpilation görevinin yapıtı. WebPack, bir giriş noktası diğer adını tanımlar main-server ; ve, bu diğer ad için bağımlılık grafiğinin çapraz geçişi clientapp/Boot-Server. TS dosyasında başlar:

entry: { 'main-server': './ClientApp/boot-server.ts' },

aşağıdaki Angular örnekte, clientapp/boot-server. ts dosyası, createServerRenderer RenderResult aspnet-prerendering sunucu işlemesini Node.js aracılığıyla yapılandırmak için npm paketinin işlevini ve türünü kullanır. Sunucu tarafı işlemeye yönelik HTML biçimlendirmesi, kesin türü belirtilmiş bir JavaScript nesnesine Sarmalanan bir Resolve işlev çağrısına geçirilir Promise . PromiseNesnenin önemi, Dom 'ın yer tutucu öğesine ekleme için sayfaya HTML işaretlemesini zaman uyumsuz olarak sağlar.

import { createServerRenderer, RenderResult } from 'aspnet-prerendering';

export default createServerRenderer(params => {
    const providers = [
        { provide: INITIAL_CONFIG, useValue: { document: '<app></app>', url: params.url } },
        { provide: 'ORIGIN_URL', useValue: params.origin }
    ];

    return platformDynamicServer(providers).bootstrapModule(AppModule).then(moduleRef => {
        const appRef = moduleRef.injector.get(ApplicationRef);
        const state = moduleRef.injector.get(PlatformState);
        const zone = moduleRef.injector.get(NgZone);
        
        return new Promise<RenderResult>((resolve, reject) => {
            zone.onError.subscribe(errorInfo => reject(errorInfo));
            appRef.isStable.first(isStable => isStable).subscribe(() => {
                // Because 'onStable' fires before 'onError', we have to delay slightly before
                // completing the request in case there's an error to report
                setImmediate(() => {
                    resolve({
                        html: state.renderToString()
                    });
                    moduleRef.destroy();
                });
            });
        });
    });
});

ASP-PreRender-veri etiketi Yardımcısı

Etiket Yardımcısı ile birlikte kullanıldığında asp-prerender-module , asp-prerender-data bağlam bilgilerini Razor görünümden sunucu tarafı JavaScript 'e geçirmek için etiket Yardımcısı kullanılabilir. Örneğin, aşağıdaki biçimlendirme Kullanıcı verilerini main-server modüle geçirir:

<app asp-prerender-module="ClientApp/dist/main-server"
        asp-prerender-data='new {
            UserName = "John Doe"
        }'>Loading...</app>

Alınan UserName bağımsız değişken YERLEŞIK JSON seri hale getirici kullanılarak serileştirilir ve params.data nesnesinde depolanır. aşağıdaki Angular örnekte, verileri bir öğesi içinde kişiselleştirilmiş bir selamlama oluşturmak için kullanılır h1 :

import { createServerRenderer, RenderResult } from 'aspnet-prerendering';

export default createServerRenderer(params => {
    const providers = [
        { provide: INITIAL_CONFIG, useValue: { document: '<app></app>', url: params.url } },
        { provide: 'ORIGIN_URL', useValue: params.origin }
    ];

    return platformDynamicServer(providers).bootstrapModule(AppModule).then(moduleRef => {
        const appRef = moduleRef.injector.get(ApplicationRef);
        const state = moduleRef.injector.get(PlatformState);
        const zone = moduleRef.injector.get(NgZone);
        
        return new Promise<RenderResult>((resolve, reject) => {
            const result = `<h1>Hello, ${params.data.userName}</h1>`;

            zone.onError.subscribe(errorInfo => reject(errorInfo));
            appRef.isStable.first(isStable => isStable).subscribe(() => {
                // Because 'onStable' fires before 'onError', we have to delay slightly before
                // completing the request in case there's an error to report
                setImmediate(() => {
                    resolve({
                        html: result
                    });
                    moduleRef.destroy();
                });
            });
        });
    });
});

Etiket yardımcılarının geçirildiği Özellik adları PascalCase gösterimi ile temsil edilir. Aynı özellik adlarının camelCase ile temsil edildiği JavaScript 'e kontrast. Varsayılan JSON serileştirme yapılandırması, bu farkından sorumludur.

Yukarıdaki kod örneğini genişletmek için, işlevine verilen özelliği hibir şekilde görüntüleyerek, veriler sunucudan görünüme geçirilebilir globals resolve :

import { createServerRenderer, RenderResult } from 'aspnet-prerendering';

export default createServerRenderer(params => {
    const providers = [
        { provide: INITIAL_CONFIG, useValue: { document: '<app></app>', url: params.url } },
        { provide: 'ORIGIN_URL', useValue: params.origin }
    ];

    return platformDynamicServer(providers).bootstrapModule(AppModule).then(moduleRef => {
        const appRef = moduleRef.injector.get(ApplicationRef);
        const state = moduleRef.injector.get(PlatformState);
        const zone = moduleRef.injector.get(NgZone);
        
        return new Promise<RenderResult>((resolve, reject) => {
            const result = `<h1>Hello, ${params.data.userName}</h1>`;

            zone.onError.subscribe(errorInfo => reject(errorInfo));
            appRef.isStable.first(isStable => isStable).subscribe(() => {
                // Because 'onStable' fires before 'onError', we have to delay slightly before
                // completing the request in case there's an error to report
                setImmediate(() => {
                    resolve({
                        html: result,
                        globals: {
                            postList: [
                                'Introduction to ASP.NET Core',
                                'Making apps with Angular and ASP.NET Core'
                            ]
                        }
                    });
                    moduleRef.destroy();
                });
            });
        });
    });
});

postListNesnenin içinde tanımlanan dizi globals tarayıcının genel window nesnesine iliştirilir. Genel kapsama açık olan bu değişken, özellikle de aynı verileri bir kez sunucuya ve istemciye yeniden yüklemeye yönelik olarak çabaların çoğaltılmasını ortadan kaldırır.

pencere nesnesine eklenen genel postList değişkeni

Web paketi geliştirme ara yazılımı

Web paketi geliştirme ara yazılımı , Web paketinin kaynakları isteğe bağlı olarak oluşturmakta olan kolaylaştırılmış bir geliştirme iş akışı Yazılım, tarayıcıda bir sayfa yeniden yüklendiğinde istemci tarafı kaynaklarını otomatik olarak derler ve sunar. Alternatif yaklaşım, üçüncü taraf bir bağımlılık veya özel kod değiştiğinde, projenin NPM derleme betiği aracılığıyla WebPack 'i el ile çağırmalıdır. Package. JSON dosyasındaki NPM derleme betiği aşağıdaki örnekte gösterilmiştir:

"build": "npm run build:vendor && npm run build:custom",

WebPack dev ara yazılım önkoşulları

ASPNET-WebPack NPM paketini yükler:

npm i -D aspnet-webpack

WebPack dev ara yazılım yapılandırması

Web paketi geliştirme ara yazılımı, Başlangıç. cs dosyasının yönteminde aşağıdaki kod aracılığıyla http istek ardışık düzenine kaydedilir Configure :

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
    app.UseWebpackDevMiddleware();
}
else
{
    app.UseExceptionHandler("/Home/Error");
}

// Call UseWebpackDevMiddleware before UseStaticFiles
app.UseStaticFiles();

Uzantı yöntemi UseWebpackDevMiddleware aracılığıyla statik dosya barındırma kaydedilmeden önce genişletme yöntemi çağrılmalıdır UseStaticFiles . Güvenlik nedenleriyle, yalnızca uygulama geliştirme modunda çalışırken ara yazılımı kaydedin.

webpack.config.js dosyanın output.publicPath özelliği, ara yazılımlar için klasörü değişiklikleri izlemesini söyler dist :

module.exports = (env) => {
        output: {
            filename: '[name].js',
            publicPath: '/dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
        },

Sık kullanılan modül değiştirme

WebPack geliştirme ara yazılımı'nın bir evrimi olarak Web paketi 'Nin sık kullanılan modül değiştirme (HMR) özelliğini düşünün. HMR aynı avantajları sunar, ancak değişiklikleri derledikten sonra sayfa içeriğini otomatik olarak güncelleştirerek geliştirme iş akışını daha da kolaylaştırır. Bunu tarayıcı yenilemesine karıştırmayın, bu da geçerli bellek içi durumu ve SPA 'nın hata ayıklama oturumunu kesintiye uğratır. Web paketi geliştirme ara yazılımı hizmeti ile tarayıcı arasında canlı bir bağlantı vardır ve bu, değişikliklerin tarayıcıya gönderildiği anlamına gelir.

Sık kullanılan modül değiştirme önkoşulları

WebPack-Hot-ara yazılım NPM paketini yükler:

npm i -D webpack-hot-middleware

Sık kullanılan modül değiştirme yapılandırması

HMR bileşeni, metotta MVC 'nin HTTP isteği ardışık düzeninde kayıtlı olmalıdır Configure :

app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions {
    HotModuleReplacement = true
});

Web paketi geliştirme ara yazılımıile doğru olduğu için, genişletme yönteminin UseWebpackDevMiddleware uzantı yönteminden önce çağrılması gerekir UseStaticFiles . Güvenlik nedenleriyle, yalnızca uygulama geliştirme modunda çalışırken ara yazılımı kaydedin.

plugins Boş bırakılmış olsa bilewebpack.config.jsdosyası bir dizi tanımlamalıdır:

module.exports = (env) => {
        plugins: [new CheckerPlugin()]

Uygulamayı tarayıcıya yükledikten sonra, Geliştirici araçlarının konsol sekmesi HMR etkinleştirmenin onayını sağlar:

Sık kullanılan modül değiştirme bağlı iletisi

Yönlendirme Yardımcıları

çoğu ASP.NET Core tabanlı maça, istemci tarafı yönlendirme genellikle sunucu tarafı yönlendirmeye ek olarak istenir. SPA ve MVC yönlendirme sistemleri, parazit olmadan bağımsız olarak çalışabilir. Ancak, bir sınır büyük/küçük harf sorunları: 404 HTTP yanıtlarını tanımlama.

Uzantısız bir yolunun kullanıldığı senaryoyu göz önünde bulundurun /some/page . İsteğin bir sunucu tarafı rotası ile eşleşmediğini, ancak deseninin bir istemci tarafı rotayla eşleştiğini varsayın. Şimdi genel olarak sunucusunda bir /images/user-512.png görüntü dosyası bulmayı bekliyor olan için gelen bir isteği göz önünde bulundurabilirsiniz. İstenen kaynak yolu herhangi bir sunucu tarafı yol veya statik dosyayla eşlenemse, istemci tarafı uygulamanın genellikle 404 HTTP durum kodu döndürerek bunu işlemesi pek — olası değildir.

Yönlendirme yardımcıları önkoşulları

İstemci tarafı yönlendirme npm paketini yükleyin. Örnek Angular bir örnek olarak Angular kullanarak:

npm i -S @angular/router

Yönlendirme yardımcıları yapılandırması

yönteminde adlı MapSpaFallbackRoute bir genişletme yöntemi Configure kullanılır:

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");

    routes.MapSpaFallbackRoute(
        name: "spa-fallback",
        defaults: new { controller = "Home", action = "Index" });
});

Yollar, yapılandırıldıkları sırayla değerlendirilir. Sonuç olarak, default önceki kod örneğinde yer alan yol ilk olarak desen eşleştirme için kullanılır.

Yeni proje oluşturma

JavaScript Hizmetleri önceden yapılandırılmış uygulama şablonları sağlar. SpaServices bu şablonlarda Angular, React ve Redux gibi farklı çerçeveler ve kitaplıklarla birlikte kullanılır.

Bu şablonlar aşağıdaki komut çalıştırarak .NET Core CLI aracılığıyla yükleyebilirsiniz:

dotnet new --install Microsoft.AspNetCore.SpaTemplates::*

Kullanılabilir SPA şablonlarının listesi görüntülenir:

Şablonlar Kısa Ad Dil Etiketler
MVC ASP.NET Core ile Angular Açısal [C#] Web/MVC/SPA
MVC ASP.NET Core ile React.js Tepki [C#] Web/MVC/SPA
React.js redux ile MVC ASP.NET Core reactredux [C#] Web/MVC/SPA

SPA şablonlarından birini kullanarak yeni bir proje oluşturmak için dotnet new komutuna şablonun Kısa Adını girin. Aşağıdaki komut, sunucu tarafı Angular MVC ASP.NET Core bir uygulama oluşturur:

dotnet new angular

Çalışma zamanı yapılandırma modunu ayarlama

İki birincil çalışma zamanı yapılandırma modu vardır:

  • Geliştirme:
    • Hata ayıklamayı kolaylaştırmak için kaynak eşlemeleri içerir.
    • İstemci tarafı kodunu performans için iyileştirmez.
  • Üretim:
    • Kaynak eşlemeleri dışlar.
    • İstemci tarafı kodunu, bundling ve minification aracılığıyla en iyi duruma getirme.

ASP.NET Core, yapılandırma modunu depolamak ASPNETCORE_ENVIRONMENT için adlı bir ortam değişkeni kullanır. Daha fazla bilgi için bkz. Ortamı ayarlama.

.NET Core CLI ile çalıştırma

Proje kökünde NuGet komutunu çalıştırarak gerekli NuGet ve npm paketlerini geri yükleme:

dotnet restore && npm i

Uygulamayı derleme ve çalıştırma:

dotnet run

Uygulama, çalışma zamanı yapılandırma moduna göre localhost'ta başlatılır. Tarayıcıda http://localhost:5000 sayfasına giderek giriş sayfası görüntülenir.

Visual Studio 2017 ile çalıştırma

dotnet new komutu tarafından oluşturulan .csproj dosyasını açın. Proje NuGet npm paketleri otomatik olarak geri yüklenir. Bu geri yükleme işlemi birkaç dakika sürebilir ve uygulama tamamlandığında çalıştırmaya hazırdır. Yeşil çalıştır düğmesine tıklayın veya Ctrl + F5 tuşuna basın; tarayıcı uygulamanın giriş sayfasını açar. Uygulama, çalışma zamanı yapılandırma moduna göre localhost üzerinde çalışır.

Uygulamayı test etme

SpaServices şablonları Karma ve Jasmine kullanarak istemci tarafı testleri çalıştırmak için önceden yapılandırılmıştır. Jasmine JavaScript için popüler bir birim testi çerçevesidir, Karma ise bu testler için test çalıştırıcısıdır. Karma, Webpack Geliştirme Ara Yazılımı ile çalışacak şekilde yapılandırılmıştır. Böylece geliştiricinin her değişiklik yapılırken testi durdurması ve çalıştırması gerekmez. İster test çalışmasına ister test çalışmasına karşı çalışan kod olsun, test otomatik olarak çalışır.

Örnek Angular olarak, CounterComponent counter.component.spec.ts dosyasındaki için iki Jasmine test örneği zaten sağlanmıştır:

it('should display a title', async(() => {
    const titleText = fixture.nativeElement.querySelector('h1').textContent;
    expect(titleText).toEqual('Counter');
}));

it('should start with count 0, then increments by 1 when clicked', async(() => {
    const countElement = fixture.nativeElement.querySelector('strong');
    expect(countElement.textContent).toEqual('0');

    const incrementButton = fixture.nativeElement.querySelector('button');
    incrementButton.click();
    fixture.detectChanges();
    expect(countElement.textContent).toEqual('1');
}));

ClientApp dizininde komut istemini açın. Şu komutu çalıştırın:

npm test

Betik, karma test çalıştırıcıyı başlatarak dosyada tanımlanan karma.conf.js okur. Diğer ayarların karma.conf.js, dizi aracılığıyla yürütülecek test dosyalarını files tanımlar:

module.exports = function (config) {
    config.set({
        files: [
            '../../wwwroot/dist/vendor.js',
            './boot-tests.ts'
        ],

Uygulamayı yayımlama

Azure'GitHub yayımlama hakkında daha fazla bilgi için bu soruna bakın.

Oluşturulan istemci tarafı varlıklarını ve yayımlanan ASP.NET Core hazır bir pakette birleştirme zahmetli olabilir. Neyse ki SpaServices, bu yayın işleminin tamamını adlı özel bir MSBuild ile organize RunWebpack eder:

<Target Name="RunWebpack" AfterTargets="ComputeFilesToPublish">
  <!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
  <Exec Command="npm install" />
  <Exec Command="node node_modules/webpack/bin/webpack.js --config webpack.config.vendor.js --env.prod" />
  <Exec Command="node node_modules/webpack/bin/webpack.js --env.prod" />

  <!-- Include the newly-built files in the publish output -->
  <ItemGroup>
    <DistFiles Include="wwwroot\dist\**; ClientApp\dist\**" />
    <ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
      <RelativePath>%(DistFiles.Identity)</RelativePath>
      <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
    </ResolvedFileToPublish>
  </ItemGroup>
</Target>

Hedef MSBuild aşağıdaki sorumluluklara sahip:

  1. npm paketlerini geri yükleme.
  2. Üçüncü taraf, istemci tarafı varlıkların üretim sınıfı bir derlemesini oluşturun.
  3. Özel istemci tarafı varlıkların üretim sınıfı bir derlemesini oluşturun.
  4. Webpack tarafından oluşturulan varlıkları yayımlama klasörüne kopyalayın.

Aşağıdaki MSBuild hedef çağrılır:

dotnet publish -c Release

Ek kaynaklar