ASP.NET Core updates in .NET 6 Preview 7

Daniel Roth

.NET 6 Preview 7 is now available and includes many great new improvements to ASP.NET Core.

Here’s what’s new in this preview release:

  • Parity with existing experiences for minimal APIs
  • Added IResult implementations for producing common HTTP responses
  • Support Request, Response and User for minimal actions
  • Minimal host and template improvements
  • Supply Blazor component parameters from the query string
  • Replace the current URI in the browser history from Blazor
  • New DynamicComponent.Instance property
  • Blazor streaming interop from JavaScript to .NET
  • Large file upload & faster file uploads with Blazor
  • Modify HTML <head> content from Blazor components
  • Support for the multiple attribute on <select> elements in Blazor
  • Support for HTTP/3 in Kestrel
  • QUIC support moved to the shared framework
  • Allow control over Activity creation
  • Support for non-ASCII characters in Kestrel response headers
  • Add W3CLogger
  • Add authentication expiration option to SignalR

Get started

To get started with ASP.NET Core in .NET 6 Preview 7, install the .NET 6 SDK.

If you’re on Windows using Visual Studio, install the latest preview of Visual Studio 2022. .NET 6 will be supported in a future public release of Visual Studio 2022 for Mac.

To get setup with .NET MAUI & Blazor for cross-platform native apps, see the latest instructions in the .NET MAUI getting started guide. Be sure to also check out the Announcing .NET MAUI Preview 7 blog post for all the details on what’s new in .NET MAUI in this release.

To install the latest .NET WebAssembly tools for ahead-of-time (AOT) compilation and runtime relinking, uninstall the earlier microsoft-net-sdk-blazorwebassembly-aot workload and install the new wasm-tools workload by running the following commands from an elevated command prompt:

dotnet workload uninstall microsoft-net-sdk-blazorwebassembly-aot
dotnet workload install wasm-tools

Upgrade an existing project

To upgrade an existing ASP.NET Core app from .NET 6 Preview 6 to .NET 6 Preview 7:

  • Update all Microsoft.AspNetCore.* package references to 6.0.0-preview.7.*.
  • Update all Microsoft.Extensions.* package references to 6.0.0-preview.7.*.

To upgrade a .NET MAUI Blazor app from .NET 6 Preview 6 to .NET 6 Preview 7 we recommend starting from a new .NET MAUI Blazor project created with the .NET 6 Preview 7 SDK and then copying code over from your original project.

See the full list of breaking changes in ASP.NET Core for .NET 6.

What’s new with minimal APIs?

Since we announced minimal APIs in .NET 6 Preview 4 we’ve been focused on enabling a more robust set of features. For .NET 6 Preview 7 we’re happy to announce that we’re lighting up more of your favorite ASP.NET experiences with a minimal twist. Let’s take a look at what you can expect.

Parity with existing experiences

Minimal APIs fundamentally change how the app startup code is structured. This meant that some of the tools and libraries we ship that interact with the app needed to be updated to handle this new pattern. The following tools and libraries have now been updated accordingly:

Added IResult implementations for producing common HTTP responses

In earlier previews, we extended IActionResult implementations from MVC to support the new IResult type introduced for minimal APIs. In this release, we’ve removed the dependency between IActionResult and IResult and added a new static Results utility class for producing common HTTP responses. Here’s an example:

app.MapPut("/todos/{id}", async (TodoDbContext db, int id, Todo todo) =>
{
    if (id != todo.Id)
    {
        return Results.BadRequest();
    }

    if (!await db.Todos.AnyAsync(x => x.Id == id))
    {
        return Results.NotFound();
    }

    db.Update(todo);
    await db.SaveChangesAsync();

    return Results.Ok();
});

Thank you Juan Barahona for contributing these IResult implementations!

Support Request, Response and User for minimal actions

In this preview, we added support for binding HttpRequest, HttpResponse and ClaimsPrincipal parameters in minimal actions. These parameters come from the Request, Response and User properties on HttpContext respectively. This is in addition to the pre-existing support for binding the HttpContext directly and a CancellationToken from HttpContext.RequestAborted.

The example below accepts the current user directly into the request handler method.

app.MapGet("/api/items", async (ITodoService service, ClaimsPrincipal user) =>
{
    return await service.GetListAsync(user.GetUserId());
})
.RequireAuthorization();

Thank you Martin Costello for contributing this feature!

Minimal host and template improvements

Minimal APIs introduced new hosting APIs and, combined with new C# features like global usings and top-level statements, enabled us to streamline the app startup experience. In this preview, we’re extending these changes to the other ASP.NET Core project templates.

For example, when you create a new ASP.NET Core Web API using the template you’ll now notice the following:

  • No Startup.cs
  • Leveraging implicit usings
  • New hosting model using WebApplication.CreateBuilder
  • Top-level statements in Program.cs (no namespace, class, or method declarations)
  • Nullable reference types

These changes reduce the amount of boilerplate code required to configure and start a new app. Note that the existing hosting model and Startup pattern will continue to be supported for existing apps.

ASP.NET Core Web API in .NET 5

image

ASP.NET Core Web API in .NET 6

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new() { Title = "WebApplication22", Version = "v1" });
});

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebApplication22 v1"));
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Check out the the .NET blog for more details on how we’re modernizing the project templates that ship with the .NET SDK.

Note about implicit using statements: Based on early feedback during implementation, changes to the implicit usings feature are being made as part of the next release, including the requirement to opt-in to implicit usings in the project file, rather than them being included by default based on the project targeting .NET 6. This will ensure they don’t impact existing projects being migrated to .NET 6 until the author is ready to enable the feature.

Supply Blazor component parameters from the query string

Blazor components can now receive parameters from the query string. To specify that a component parameter of a routable component can come from the query string, apply the [SupplyParameterFromQuery] attribute in addition to the normal [Parameter] attribute:

@page "/search"

<h1>Search</h1>

<p>Filter: @Filter</p>

<p>Page: @Page</p>

<p>Assignees:</p>
<ul>
    @foreach (var assignee in Assignees)
    {
        <li>@assignee</li>
    }
</ul>

@code {
    // Handles URL patterns like /search?filter=some+stuff&page=3&assignee=Monica&assignee=Chandler

    [Parameter]
    [SupplyParameterFromQuery]
    public string Filter { get; set; }

    [Parameter]
    [SupplyParameterFromQuery]
    public int? Page { get; set; }

    [Parameter]
    [SupplyParameterFromQuery(Name = "assignee")]
    public string[] Assignees { get; set; }
}

Blazor search query

Component parameters supplied from the query string may be of the following types:

  • String, bool, DateTime, decimal, double, float, Guid, int, long.
  • Nullable variants of the above types (except string – not applicable).
  • Arrays of the above types, nullable or not.

Replace the current URI in the browser history from Blazor

When calling NavigationManager.NavigateTo in a Blazor app, you can now specify that you want to replace the current URI in the browser history instead of pushing a new URI onto the history stack. To replace the current URI in the browser history, specify true for the new replace parameter:

@NavigationManager.NavigateTo("Other", replace: true)

New DynamicComponent.Instance property

DynamicComponent now has an Instance property that provides a convenient way to get access to the dynamically created component instance:

<DynamicComponent Type="typeof(MyComponent)" @ref="dc" />

<button @onclick="Refresh">Refresh</button>

@code {
    DynamicComponent dc;
    Task Refresh()
    {
        return (dc.Instance as IRefreshable)?.Refresh();
    }
}

Blazor streaming interop from JavaScript to .NET

Blazor now supports streaming data directly from JavaScript to .NET. Streams are requested using the new IJSStreamReference interface:

JavaScript

function jsToDotNetStreamReturnValue() {
    return new Uint8Array(10000000);
}

C#

  var dataReference = await JSRuntime.InvokeAsync<IJSStreamReference>("jsToDotNetStreamReturnValue");
  using var dataReferenceStream = await dataReference.OpenReadStreamAsync(maxAllowedSize: 10_000_000);

  // Write JS Stream to disk
  var outputPath = Path.Combine(Path.GetTempPath(), "file.txt");
  using var outputFileStream = File.OpenWrite(outputPath);
  await dataReferenceStream.CopyToAsync(outputFileStream); 

Large file upload & faster file uploads with Blazor

Using the new Blazor streaming interop support mentioned above, we now support uploading files larger than 2GB using the InputFile component. The updated InputFile component is also much more efficient at uploading files thanks to native byte[] streaming, which avoids expensive Base64 encoding.

Modify HTML <head> content from Blazor components

Blazor now has built-in support for modifying HTML <head> element content from components, including setting the <title> and adding <meta> elements.

To specify the page’s title from a component, use the new PageTitle component. The HeadContent component can be used to render other content to the <head>.

<PageTitle>@title</PageTitle>

<HeadContent>
    <meta name="description" content="@description">
</HeadContent>

@code {
    private string description = "Description set by component";
    private string title = "Title set by component";
}

To enable the functionality provided by PageTitle and HeadContent, you need to add a HeadOutlet root component to your application. In Blazor WebAssembly, this can be done by adding the following line in Program.Main:

builder.RootComponents.Add<HeadOutlet>("head::after");

In Blazor Server, the setup is slightly more involved. In order to support prerendering, the App root component needs to be rendered before the HeadOutlet. A convenient way to achieve this is to move most of the content in _Host.cshtml to _Layout.cshtml, as shown below.

_Layout.cshtml

@using Microsoft.AspNetCore.Components.Web
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>Blazor Server App</title>
    <base href="~/" />
    <component type="typeof(HeadOutlet)" render-mode="ServerPrerendered" />
</head>
<body>
    @RenderBody()
    <script src="_framework/blazor.server.js"></script>
</body>
</html>

_Host.cshtml

@page "/"
@namespace BlazorServerWeb_CSharp.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
    Layout = "_Layout";
}

<component type="typeof(App)" render-mode="ServerPrerendered" />

A future release will include updated Blazor project templates, so performing these changes to enable <head> modification won’t be necessary for new projects.

Support for the multiple attribute on <select> elements in Blazor

If you specify the multiple attribute in a <select> elements from a Blazor component, the onchange event will now supply an array of the selected elements via ChangeEventArgs. Likewise, array values can be bound to the value attribute when multiple is specified.

<p>
    Select one or more cars: 
    <select @onchange="SelectedCarsChanged" multiple>
        <option value="audi">Audi</option>
        <option value="jeep">Jeep</option>
        <option value="opel">Opel</option>
        <option value="saab">Saab</option>
        <option value="volvo">Volvo</option>
    </select>
</p>

<p>
    Select one or more cities: 
    <select @bind="SelectedCities" multiple>
        <option value="bal">Baltimore</option>
        <option value="la">Los Angeles</option>
        <option value="pdx">Portland</option>
        <option value="sf">San Francisco</option>
        <option value="sea">Seattle</option>
    </select>
</p>

@code {
    public string[] SelectedCars { get; set; } = new string[] { };
    public string[] SelectedCities { get; set; } = new[] { "bal", "sea" };

    void SelectedCarsChanged(ChangeEventArgs e)
    {
        SelectedCars = (string[])e.Value;
    }
}

When using <InputSelect>, the multiple attribute is inferred if the bound value has an array type.

<EditForm EditContext="@editContext">
    Select one or more classifications (Minimum: 2, Maximum: 3):
    <InputSelect @bind-Value="starship.SelectedClassification">
        <option value="@Classification.Exploration">Exploration</option>
        <option value="@Classification.Diplomacy">Diplomacy</option>
        <option value="@Classification.Defense">Defense</option>
        <option value="@Classification.Research">Research</option>
    </InputSelect>
</EditForm>

@code {
    private EditContext editContext;
    private Starship starship = new();

    protected override void OnInitialized()
    {
        editContext = new(starship);
    }

    private class Starship
    {
        [Required, MinLength(2), MaxLength(3)]
        public Classification[] SelectedClassification { get; set; } =
            new[] { Classification.Diplomacy };
    }

    private enum Classification { Exploration, Diplomacy, Defense, Research }
}

Preview support for HTTP/3 in Kestrel

Preview 7 introduces early support for HTTP/3 and QUIC in Kestrel to try out and give feedback on.

HTTP/3 is the third and upcoming major version of HTTP. HTTP/3 uses the same semantics as HTTP/1.1 and HTTP/2: the same request methods, status codes, and message fields apply to all versions. The differences are in the underlying transport. Both HTTP/1.1 and HTTP/2 use TCP as their transport. HTTP/3 uses a new transport technology developed alongside HTTP/3 called QUIC.

HTTP/3 and QUIC have a number of benefits compared to older HTTP versions:

  • Faster response time of the first request. QUIC and HTTP/3 negotiates the connection in fewer round-trips between the client and the server. The first request reaches the server faster.
  • Improved experience when there is connection packet loss. HTTP/2 multiplexes multiple requests via one TCP connection. Packet loss on the connection would affect all requests. This problem is called “head-of-line blocking”. Because QUIC provides native multiplexing, lost packets only impact the requests where data has been lost.
  • Supports transitioning between networks. This feature is useful for mobile devices where it is common to switch between Wi-Fi and cellular networks as a mobile device changes location. Today HTTP/1.1 and HTTP/2 connections will fail with an error and force an app or web browser to retry. HTTP/3 allows the app or web browser to seamlessly continue when a network changes. Kestrel doesn’t support network transitions in .NET 6, but we’ll explore adding it in a future .NET release.

To start using HTTP/3, configure the QUIC transport, and modify ListenOptions to add an HTTP/3 binding. For use with browser-based clients, you’ll also need to enable sending the alt-svc header.

    var builder = WebApplication.CreateBuilder(args);
    builder.WebHost.UseKestrel()
    // Set up Quic options
    .UseQuic(options =>
    {
        options.Alpn = "h3-29";
        options.IdleTimeout = TimeSpan.FromMinutes(1);
    })
    .ConfigureKestrel((context, options) =>
    {
        options.EnableAltSvc = true;
        options.Listen(IPAddress.Any, 5001, listenOptions =>
        {
            // Use Http3
            listenOptions.Protocols = HttpProtocols.Http1AndHttp2AndHttp3;
            listenOptions.UseHttps();
        });
    });

HTTP/3 is not supported everywhere. See use HTTP/3 with the ASP.NET Core Kestrel web server for information on getting started with HTTP/3 in Kestrel.

QUIC support moved to the shared framework

We’re no longer shipping the Microsoft.AspNetCore.Server.Kestrel.Transport.Quic package, and are instead including the assembly in the ASP.NET Core shared framework. Customers with a PackageReference to Microsoft.AspNetCore.Server.Kestrel.Transport.Quic should remove the PackageReference from their project.

Allow control over Activity creation

We’ve added support for DistributedContextPropagators in ASP.NET Core. Prior to this change, ASP.NET Core had knowledge of the W3C TraceContext and W3C Baggage specifications and we created an Activity only if the tracestate and traceparent HTTP headers were present on the incoming HTTP request. This made it impossible to support other tracing specifications. It’s now possible to support other distributed tracing specifications by implementing a custom DistributedContextPropagator and registering it in the DI container.

Support for non-ASCII characters in Kestrel response headers

Kestrel now has support for sending non-ASCII characters in HTTP response headers. To opt-in custom encoding on per-header basis, you can provide a ResponseHeaderEncodingSelector:

builder.WebHost.ConfigureKestrel(options =>
{
    options.ResponseHeaderEncodingSelector = (_) => Encoding.ASCII;
});

Note: While use of custom response header encoding may be needed in some cases, we discourage the use of non-ASCII encodings to avoid compatibility issues with other HTTP clients.

Add W3CLogger

ASP.NET Core is now capable of generating server access logs in the W3C Extended Log File Format. To start emitting server access logs, you need to add the logger to DI and add the W3C logging middleware to your middleware pipeline:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddW3CLogging(options =>
{
    options.LogDirectory = @"C:\logs";
    options.LoggingFields = W3CLoggingFields.Request | W3CLoggingFields.ConnectionInfoFields;
});

var app = builder.Build();

app.UseW3CLogging();
if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

app.MapGet("/", () => "Hello World!");
app.Run();

This will produce a log file that resembles this output:

#Version: 1.0
#Start-Date: 2021-08-10 01:07:40
#Fields: c-ip s-ip s-port cs-method cs-uri-stem cs-uri-query cs-version cs-host cs(User-Agent) cs(Referer)
::1 ::1 5001 GET / - HTTP/2 localhost:5001 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/92.0.4515.131+Safari/537.36+Edg/92.0.902.67 -
::1 ::1 5001 GET /favicon.ico - HTTP/2 localhost:5001 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/92.0.4515.131+Safari/537.36+Edg/92.0.902.67 https://localhost:5001/
::1 ::1 5001 GET / - HTTP/2 localhost:5001 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/92.0.4515.131+Safari/537.36+Edg/92.0.902.67 -
::1 ::1 5001 GET / - HTTP/2 localhost:5001 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/92.0.4515.131+Safari/537.36+Edg/92.0.902.67 -
::1 ::1 5001 GET / - HTTP/2 localhost:5001 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/92.0.4515.131+Safari/537.36+Edg/92.0.902.67 -

Add authentication expiration option to SignalR

There is a new option that will enable SignalR to track the expiration of an authentication token and close the connection if the token expires. This option can be enabled with CloseOnAuthenticationExpiration on HttpConnectionDispatcherOptions as shown below.

app.UseEndpoints(endpoints =>
{
    endpoints.MapHub<MyHub>("/hub", options =>
    {
        options.CloseOnAuthenticationExpiration = true;
    });
});

Give feedback

We hope you enjoy this preview release of ASP.NET Core in .NET 6. We’re eager to hear about your experiences with this release. Let us know what you think by filing issues on GitHub.

Thanks for trying out ASP.NET Core!

83 comments

Discussion is closed. Login to edit/delete existing comments.

  • Craig Johnson 0

    .NET 6 is looking awesome! Took about 20 minutes to migrate our app to it and then another few minutes to wire up ErrorBoundary and replace our home-grown DynamicComponent. Looking forward to the go-live!!

    • Daniel RothMicrosoft employee 0

      Awesome, that’s great to hear, Craig! Thanks for trying out the .NET 6 previews.

  • George Darchiashvili 0

    wasm-tools installation fails.
    “Workload installation failed: microsoft.ios.sdk::15.0.100-preview.7182 is not found in NuGet feeds https://api.nuget.org/v3/index.json;C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\”.”

    • Daniel RothMicrosoft employee 0

      Hi George. Thanks for trying out the new .NET 6 preview! What workload install command are you running exactly? This is a known issue when installing the maui workload, but shouldn’t happen with the wasm-tools workload. To install .NET MAUI, you’ll need to use the maui-check tool for this preview release.

      • Emmanuel Adebiyi 0

        Awesome stuff. .NET 6 is definitely living up to it’s promise

      • Walid Riabi 0

        Hi, I have the same error message when i execute “dotnet workload install wasm-tools”

        • Daniel RothMicrosoft employee 0

          Thanks for reporting this, Walid! Could you please open a GitHub issue for this with details on the specific .NET versions and workloads you have installed so that we can try to reproduce this? https://github.com/dotnet/aspnetcore/issues/new.

        • Daniel RothMicrosoft employee 0

          One thing you can try to work around this issue is to first make sure you only have the official NuGet feed configured, and then rename your dotnet/metadata folder to something else before trying to install the workload again.

  • Daniel P 0

    Hi,

    I’d like to take my existing Blazor WASM app and publish it as an Android app using .NET MAUI Blazor. Is there any official/unofficial documentation on how to proceed?

    Thanks!

    • Daniel RothMicrosoft employee 0

      Hi Daniel. We don’t have docs for this yet, but basically what you do is move your components into a common Razor class library, and then reference that library from your Blazor WebAssembly app and the .NET MAUI Blazor app. The same components should work in both.

      • noseratio 0

        Hi Danial, BlazorWebView looks really promising as a C#-only alternative to Electron, but as of .NET 6 RC1 it has serious keyboard/focus issues, at least on Windows Desktop. It really doesn’t feel usable at this stage: https://github.com/dotnet/maui/issues/2341. Is there a chance it could be fixed for .NET 6 release?

        • Daniel RothMicrosoft employee 0

          Thanks for reporting this issue! We’ll take a look.

  • Yasser SASSI 0

    He Daniel,
    Seems awesome, any updates on HotReload?

    • Daniel RothMicrosoft employee 0

      Hi Yasser. Things are starting to come together for .NET Hot Reload in Visual Studio 2022. The experience is only partially implemented in Visual Studio 2022 Preview 3, but expect more .NET Hot Reload updates soon.

  • Tanvir Ahmad Arjel 0

    Hi Daniel Roth,

    Why [SupplyParameterFromQuery] instead of just [FromQuery]? [SupplyParameterFromQuery] looks weird to read.

    • Daniel RothMicrosoft employee 0

      Hi Tanvir. Thanks for this feedback! It’s tempting to use the existing [FromQuery] attribute but problematic because it has dependencies that we don’t want in Blazor and we can’t guarantee that it’s parameters will always make sense for Blazor apps. So we introduced a new attribute with a new name to avoid name collisions with the existing attribute. If you have suggestions for a better name please let us know!

      • Jacob McDowell 0

        Brainstorming a bit, [QueryStringParameter] makes sense to me – could be used with or without [Parameter]:
        [QueryStringParameter] without [Parameter] means it can only come from the query string, stacking them means it could come from either the query string or original [Parameter] passing.

      • Leonardo Bosquett 0

        Hello there, just giving some suggestions to name:
        [QueryParameter]
        [UrlQueryParameter]
        [FromUrlQuery]
        [BindFromQuery]
        [QueryBind]

      • Marvin Groß 0

        If you have to write [Parameter] already, why not simply add another not required bool to Parameter?

        For example:
        [Parameter(fromQuery: true)]

        Default is false. No need to learn a new attribute and no conflicts with existing projects

        • Nathan Berkowitz 0

          I like this idea.

          [Parameter(fromQuery: true)]

          or

          [QueryParameter]

          Thanks

  • J. Kramer 0

    I tried “Modify HTML content from Blazor components” and it works, so now I’m trying (for the first time) to modify the head content from regular Blazor WASM pages, but can’t find any info on how to do that except for some 3rd party JS libraries. I’ve searched the Internet and read the previous Dev Blogs ASP.NET Core Updates and I found Influencing the HTML head in Blazor apps ( .NET 5 Preview 8) but that Nuget package isn’t updated anymore. I think I missed something?

    • Daniel RothMicrosoft employee 0

      Hi J. Kramer. The instructions above should have everything you need to setup modifying the <head> contents from a Blazor WebAssembly app. To modify the title use the new PageTitle component. To modify the head content use the HeadContent component. To set this up in a Blazor WebAssembly app you need to add the HeadOutlet component as a root component: builder.RootComponents.Add<HeadOutlet>("head::after");. We had tried to introduce a mechanism in .NET 5 for modifying the head, but it ended up having issues, so we’re going with a different approach in .NET 6.

      • J. Kramer 0

        Thank you for your reply, At first I thought there was different code needed for normal ‘Blazor WASM Pages’ and ‘Blazor WASM Components’. But everything is a component in Blazor. Why it didn’t work in the beginning is because (in my case) I needed to put:

        builder.RootComponents.Add("head::after");

        before/above

        builder.RootComponents.Add("#app");
        • Daniel RothMicrosoft employee 0

          Ah, good point! The order does matter. Otherwise the PageTitle components don’t have a chance to render before the HeadOutput component tries to add to the HTML head.

        • Daniel RothMicrosoft employee 0

          Actually, hold on. You’ve got it backwards. You need the order to be like this:

          builder.RootComponents.Add<App>("#app");
          builder.RootComponents.Add<HeadOutlet>("head::after");
  • John King 0

    minimal APIs ??
    Toy project then Toy language and toy platform future ?
    I don’t get why MS is doing this , does it because Azure Function ?

    As the community leader , that MS not lead us to better design pattern , better compose pattern , better isolation pattern, better project separation pattern ,
    instead, that MS now tech us to use bad design with less code, bad compose pattern with hand writing more code or use template (you have to write your template and with more code) , bad isolation pattern (no asp.net core app’s have a plugin system we use in .net 4.x) , project separation always kick our ass.

    And everything is rush to be release :
    blazor ? I interesting it as a devloper , and I will never choose it for business , because Angualr/React/Vue is better , and JS is design for web, why we need WASM, because we need fast algorithms for image/video, we do not need a slower WASM for web ! and the normal/right for .net in WASM , is to support library(algorithms) compile to native WASM, and let JS to call it , then develop Blazor to have better intergation for the compiled native WASM .

    And there no GPU standard, everyone is pain with the Image /Graphic in .net (I want to thanks for ImageSharp team to bring us CPU image )
    There are no WASM compile standard, you can not mapping C# class / method in a library to expose to js runtime.

    I feel MS is really rush at something, and really love to create new things (but not better and less pain in the new things ) it’s not innovate , instead , it split us from one big community into smaller community , and that means less nuget package can be use in our scenario (they are not universal for different scenario)

    • Daniel RothMicrosoft employee 0

      Hi John. Thanks for raising your concerns with us.

      minimal APIs ?? I don’t get why MS is doing this , does it because Azure Function ?

      The simplifications to API development and ASP.NET Core hosting are to help new users onboard to ASP.NET Core more easily. The existing ASP.NET Core patterns, while still valid, require a significant number of files and lines of code to create even a single endpoints. This additional complexity isn’t needed if you’re just trying to get started or build something simple. The new minimal patterns provide a much easier onramp. But these new patterns also aren’t toys. They offer superior performance and sufficient flexibility to scale up to large app development.

      As the community leader , that MS not lead us to better design pattern , better compose pattern , better isolation pattern, better project separation pattern ,

      We do our best to encourage best practices needed for the most demanding of workloads, but we also need to balance that with providing sufficient flexibility for a variety of app scenarios. What might be considered good design and factoring for one scenario can also be excessive complexity for a different scenario.

      blazor ? I interesting it as a devloper , and I will never choose it for business , because Angualr/React/Vue is better , and JS is design for web

      Blazor is all about giving developers the choices to use the languages, tools, and frameworks that work best for them. If you prefer using existing JS frameworks, that’s great! ASP.NET Core works great with existing JS frameworks. But for many developers, being able to use .NET & C# for client web UI development is liberating and empowering. Using Blazor does come with certain tradeoffs, but it is more than sufficient for many scenarios.

      I feel MS is really rush at something, and really love to create new things … it split us from one big community into smaller community , and that means less nuget package can be use in our scenario (they are not universal for different scenario)

      I think that’s a valid criticism. There are parts of the .NET ecosystem today that are fragmented, and any new efforts need to be carefully considered to avoid further fragmentation. For the past couple of releases we’ve been working towards a unification strategy (One .NET) to get all of .NET onto a common runtime and set of libraries. ASP.NET Core is built to be a unified web framework. .NET MAUI unifies xplat mobile and desktop scenarios into .NET 6. We’re not there yet, but we’re making progress on multiple fronts.

      • John King 0

        don’t get me wrong, that your team are doing really good on .net , but in some scenario, you’r doing for simple usage (which may only be used as a demo ). the truth is less is more , you can do some helper methods like the WebHost.CreateDefaultBuilder , but then a lots of new developer also do not know what does it do for you. I come from Asp.Net Core 1.0 so I know what it do for me , setup loging, IIS, args etc. but what about new developers ? where do they lean what does it did for you ? after all : Less code is more work/lean

        and I’m really upset that Asp.Net Core team do not give us a prop way to compose/organize our project. Yes , today many of us start to working micro service, but look at JAVA’s Spring and ABP for .Net, they also service for micro services and they can do single application too , but they give you a really good pattern to organize and share your code/nuget packages ! Do you still know why we create a separated DLL after all those yeas using nuget ? Share and DRY (do not repeat your self) , but can you say asp.net core is doing a good job on this ? ABP organize your code to a shareable module and you can install to your app with 1 simple line code to enable it. and Ask you self , What will you choose [a simple way or a better organize way] to develop your business app/services for your complex company business ? And MVC still have many issue that not been solved and do not provide a good project separate pattern (different area in different project), and your team just goes to blazer anyway.

        IMO, the project system need a virtual file system and it should be access-able from code , then we can use it to make it work for develop mode and release mod easier (think about the wwwroot folder in different project). the multi-plugin app also can use it to simplify the work to run the plugin.

        • Daniel RothMicrosoft employee 0

          Asp.Net Core team do not give us a prop way to compose/organize our project

          It sounds like this deserves a more in depth conversation than what we can really do in these blog post comments. Do you want to create a GitHub issue to start discussion on this? https://github.com/dotnet/aspnetcore/issues/new.

          This is actually the first I’ve heard of ABP, so thanks for brining it to my attention!

    • Erik 0

      Hi Ricardo, I agree with you that it would be great to have “.NET WebAssembly library” project that compiles to native WASM and has debugging support. But what is excellent about Blazor now is that you can reuse existing .NET code, and I appreciate the work done by the Blazor team. One of the most significant limitations is threading support until the WebAssembly threads will be widely adopted.

    • HwanHo Lee 0

      I think minimal api will be useful in an intranet environment. In my case, I had several independent monitoring systems, each running a client and had to run a server program separately. Imagine how a minimal api could improve this case. and that is i wanted

  • Rajiv Kumar 0

    Very happy to see .Net improving the command line install experience. But most of the users in enterprise will not have admin rights. Is there way to install these workloads without elevated permission?

    • Kathleen DollardMicrosoft employee 0

      Workloads for an admin SDK install need to be installed with elevated permissions. Workloads for non-admin SDK installs do not need elevated positions.

      Often, admin installs are done via the SDK installer and non-admin installs are done via scripts, although the key thing is that workloads are in the same file location as the SDK and that determines elevation.

  • Ricardo Francisco 0

    In the last couple of months, I’ve developed a couple of internal applications using Blazor mostly as a way to show my colleagues some of the things I like in dotnet. And from my experience, I can tell you a couple of things that I would need to be comfortable using in our products and external projects:
    – Better IDE Support. VS Mac is horribly slow, and VsCode simply doesn’t work with Blazor. 99% of the time I have no IntelliSense or the pages show squiggly lines everywhere.
    – Better performance (it’s very easy to make mistakes that make the applications very show, and it’s hard and time-consuming to fix it, if at all possible)
    – A good component library officially supported by MS, like Angular Material is supported by the angular team. There are a couple of component projects out there, but they are just too young/unstable to be used in large projects/products.
    – Better ecosystem. Since blazor is still relatively new, and the community small, the number of packages available is minuscule when comparing with Angular, React, or even Vue.
    – Better guidance and realistic example applications using it. The template projects are just too basic, and the pizza delivery apps are not much better.

    Don’t get me wrong, I really enjoy Blazor. But it still has ways to go until it can compete with other technologies, and I’m not sure how sure/committed MS is with it (will it be the next SilverLight?)

    • Daniel RothMicrosoft employee 0

      Hi Ricardo. Thanks for this thoughtful feedback!

      Better IDE support for working with Razor is one of our top priorities. Right now we are focused on revamping the Razor editing support in Visual Studio 2022, but the goal is to have consistently good Razor editing across the Visual Studio family of editors.

      I’d love to hear more about the performance pit falls your ran into. Would you be willing to file a GitHub issue with some more details? We do have some performance guidance in the Blazor docs. It would be great to verify if the issues you hit are covered in our guidance, or if we could improve the framework to avoid the pitfalls altogether.

      We have avoided building our own component library into Blazor because we want to leave space for the community to innovate and instead focus our efforts on improving the framework. There are component library offerings from a variety of component vendors including Telerik, DevExpress, Syncfusion, Infragistics, GrapeCity, and jQWidgets. There are also a variety of free open source offerings including Radzen, MudBlazor, MatBlazor, Blazorise, Blazored, and others.

      There are now also Blazor component wrappers for the official Fluent UI web components.

      For realistic example apps, can you point me to some examples of sample apps that exhibit the level of complexity and scenarios that you are interested (yes, I did just ask for an example example app 😆).

  • Mike-E 0

    Hey Mr. Roth and team: I am finally upgrading to Visual Studio 2022 and my Blazor Server-side experience is SO MUCH BETTER! Thank you SO MUCH for putting this all together, as well as putting up with my kicking and screaming over the past several months re: performance and sluggishness in Visual Studio.

    It appears all the memory-related problems have been addressed and things are so much better in VS2022. Looking forward to stretching its legs once I get everything upgraded to net6.0.

    Speaking of which. 😁 I did try to upgrade a Razor component library to the latest .net6.0 on VS2022 Preview 3.0 and I am getting the following warning:

    CSC : warning CS8032: An instance of analyzer Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator cannot be created from C:\Program Files\dotnet\sdk\6.0.100-preview.7.21379.14\Sdks\Microsoft.NET.Sdk.Razor\source-generators\Microsoft.NET.Sdk.Razor.SourceGenerators.dll : Could not load file or assembly 'Microsoft.CodeAnalysis, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified..

    I wanted to point it out to see if there’s an easy fix and/or if I should report it to a repository somewhere. Thanks again for all your great work out there. You have no idea how much you impact the lives of developers such as myself who dream to build a business on Microsoft technology. 👍

    EDIT: I knew I would figure this on my own if I posted something here. 😁 I got the grand idea of searching on GitHub repository and sure enough was reported yesterday: https://github.com/dotnet/aspnetcore/issues/35283

    • Mike-E 0

      FWIW I fixed that issue but ran into another one. Apparently, there is a very obvious NuGet versioning issue that is keeping Razor projects from being upgraded to Preview 7. I am surprised that I haven’t seen anything mentioned here in the comments about this yet:

      https://github.com/dotnet/aspnetcore/issues/35300#issuecomment-897877459

      • Daniel RothMicrosoft employee 0

        Hi Mike-E. Thanks for kicking the tires with Visual Studio 2022. It’s great to hear that things are working better! Hopefully we’ll get https://github.com/dotnet/aspnetcore/issues/35300 resolved soon. Sorry about the frustration!

Feedback usabilla icon