ASP.NET Core updates in .NET 8 Preview 4
.NET 8 Preview 4 is now available and includes many great new improvements to ASP.NET Core.
Here’s a summary of what’s new in this preview release:
- Blazor
- Streaming rendering with Blazor components
- Handling form posts with Blazor SSR
- Route to named elements in Blazor
- Webcil packaging for Blazor WebAssembly apps
- API authoring
- Expanded support for form binding in minimal APIs
- API project template includes
.http
file
- Native AOT
- Logging and exception handling in compile-time generated minimal APIs
- ASP.NET Core top-level APIs annotated for trim warnings
- Reduced app size with configurable HTTPS support
- Worker Service template updates
- Additional default services configured in the slim builder
- API template JSON configuration changes
- Support for JSON serialization of compiler-generated
IAsyncEnumerable
unspeakable types
- Authentication and authorization
- Identity API endpoints
- Improved support for custom authorization policies with
IAuthorizationRequirementData
- ASP.NET Core metrics
For more details on the ASP.NET Core work planned for .NET 8 see the full ASP.NET Core roadmap for .NET 8 on GitHub.
Get started
To get started with ASP.NET Core in .NET 8 Preview 4, install the .NET 8 SDK.
If you’re on Windows using Visual Studio, we recommend installing the latest Visual Studio 2022 preview. Visual Studio for Mac support for .NET 8 previews isn’t available at this time.
Upgrade an existing project
To upgrade an existing ASP.NET Core app from .NET 8 Preview 3 to .NET 8 Preview 4:
- Update the target framework of your app to
net8.0
. - Update all Microsoft.AspNetCore.* package references to
8.0.0-preview.4.*
. - Update all Microsoft.Extensions.* package references to
8.0.0-preview.4.*
.
See also the full list of breaking changes in ASP.NET Core for .NET 8.
Blazor
Streaming rendering with Blazor components
You can now stream content updates on the response stream when using server-side rendering (SSR) with Blazor in .NET 8. Streaming rendering can improve the user experience for server-side rendered pages that need to perform long-running async tasks in order to render fully.
For example, to render a page you might need to make a long running database query or an API call. Normally all async tasks executed as part of rendering a page must complete before the rendered response can be sent, which can delay loading the page. Streaming rendering initially renders the entire page with placeholder content while async operations execute. Once the async operations completes, the updated content is sent to the client on the same response connection and then patched by Blazor into the DOM. The benefit of this approach is that the main layout of the app renders as quickly as possible and the page is updated as soon as the content is ready.
To enable streaming rendering, you’ll first need to add the new Blazor script.
<script src="_framework/blazor.web.js" suppress-error="BL9992"></script>
Note that if you’re adding this script to a Blazor component, like your layout component, you’ll need to add the suppress-error="BL9992"
attribute to avoid getting an error about using script tags in components.
Then, to enable streaming rendering for a specific component, use the [StreamRendering(true)]
attribute. Typically this is done using the @attribute
Razor directive:
@page "/fetchdata"
@using BlazorSSR.Data
@inject WeatherForecastService ForecastService
@attribute [StreamRendering(true)]
<PageTitle>Weather forecast</PageTitle>
<h1>Weather forecast</h1>
@if (forecasts is null)
{
<p><em>Loading...</em></p>
}
else
{
// Render weather forecasts
}
@code {
private string message;
protected override async Task OnInitializedAsync()
{
forecasts = await ForecastService.GetForecastAsync(DateOnly.FromDateTime(DateTime.Now));
}
}
The component will now initially render without waiting for any async tasks to complete using placeholder content (“Loading…”). As the async tasks complete, the updated content is streamed to the response and then patched by Blazor into the DOM.
Handling form posts with Blazor SSR
You can now use Blazor components to handle form posts with server-side rendering.
To enable handling form submissions from the server, you first need to setup a model binding context using the CascadingModelBinder
component. An easy way to do this is in the main layout of your app:
<CascadingModelBinder>
@Body
</CascadingModelBinder>
To define a form in Blazor you use the existing EditForm
component and the corresponding input components, like InputText
, InputSelect
, etc.
The EditForm
component will render a standard HTML form
element, so you can use the method
attribute to specify if the form should send POST request. The EditForm
event handlers are not supported with GET requests.
When the form is submitted, the request will be routed to the corresponding page and then handled by the form with the matching form handler name as specified by the handler
query string parameter. You can specify the form handler name for an EditForm
using the FormHandlerName
attribute. If there’s only one form on the page, then you don’t need to specify a name. You can then handle the form submission using the EditForm
events.
Support for model binding and validating the request data hasn’t been implemented yet (it’s coming!), but you can manually handle the request data using the FormDataProvider
service. The FormDataProvider.Entries
property provides access to the form data and the FormDataProvider.Name
property specifies the intended form handler.
Here’s what a simple server-side rendered form in Blazor looks like:
@inject FormDataProvider FormData
<EditForm method="POST" Model="exampleModel" OnValidSubmit="HandleSubmit">
<InputText @bind-Value="exampleModel.Name" />
<button type="submit">Submit</button>
</EditForm>
@code {
ExampleModel exampleModel = new();
protected override void OnInitialized()
{
// Manually model bind the form data using the FormDataProvider service
if (FormData.Entries.TryGetValue("Name", out var nameValues))
{
exampleModel.Name = nameValues.First();
}
}
void HandleSubmit()
{
// Handle the submitted form data
}
public class ExampleModel
{
public string? Name { get; set; }
}
}
Route to named elements in Blazor
Blazor now supports using client-side routing to navigate to a specific HTML element on a page using standard URL fragments. If you specify an identifier for an HTML element using the standard id
attribute, Blazor will correctly scroll to that element when the URL fragment matches the element identifier.
Webcil packaging for Blazor WebAssembly apps
You can now try out the new Webcil package with Blazor WebAssembly apps. Webcil is web-friendly packaging of .NET assemblies that removes any content specific to native Windows execution to avoid issues when deploying to environments that block the download or use of .dll files.
To enable use of Webcil for your Blazor WebAssembly apps, add the WasmEnableWebcil
property to your project file:
<PropertyGroup>
<WasmEnableWebcil>true</WasmEnableWebcil>
</PropertyGroup>
If you encounter issues with using .webcil files in your environment, please let us know by creating an issue on GitHub.
API authoring
Expanded support for form binding in minimal APIs
This preview introduces expanded support for binding to form types in minimal APIs.
Form-based parameters are now inferred without the need of the FromForm
attribute.
Support for form-based parameters includes: IFormCollection
, IFormFile
, and IFormFileCollection
. OpenAPI metadata is inferred for form parameters to support integration with Swagger UI.
The code sample below showcases implementing a minimal API that handles file uploads by leveraging inferred binding from the IFormFile
type.
var app = WebApplication.Create();
string GetOrCreateFilePath(string fileName, string filesDirectory = "uploadFiles")
{
var directoryPath = Path.Combine(app.Environment.ContentRootPath, filesDirectory);
Directory.CreateDirectory(directoryPath);
return Path.Combine(directoryPath, fileName);
}
async Task UploadFileWithName(IFormFile file, string fileSaveName)
{
var filePath = GetOrCreateFilePath(fileSaveName);
await using var fileStream = new FileStream(filePath, FileMode.Create);
await file.CopyToAsync(fileStream);
}
app.MapPost("/upload", async (IFormFile file) => {
var fileSaveName = Guid.NewGuid().ToString("N") + Path.GetExtension(file.FileName);
await UploadFileWithName(file, fileSaveName);
return TypedResults.Ok("File uploaded successfully!");
});
app.Run();
This feature is supported in minimal APIs that use runtime-based code generation and in minimal APIs leveraging the new compile-time code generation for Native AOT scenarios.
Note: It’s important to be defensive against XSRF attacks when implementing forms in an application. This code sample outlines how to use the anti-forgery services in ASP.NET to support the generation and validation of anti-forgery tokens in minimal APIs.
API project template includes .http
file
The API project template (generated via dotnet new api
) now includes an .http
file that can be used to send requests to the endpoints defined within the application from the new HTTP editor in Visual Studio.
@MyApi_HostAddress = http://localhost:5233
GET {{MyApi_HostAddress}}/todos/
Accept: application/json
###
GET {{MyApi_HostAddress}}/todos/1
Accept: application/json
###
Native AOT
Logging and exception handling in compile-time generated minimal APIs
Minimal APIs generated at runtime support automatically logging (or throwing exceptions in Development environments) when parameter binding fails. In this preview, we introduce the same support for APIs generated at compile-time via the Request Delegate Generator (RDG).
Consider the following API endpoints where we’ve enabled using the RDG by setting <EnableRequestDelegateGenerator>true</EnableRequestDelegateGenerator>
:
var app = WebApplication.Create();
app.MapGet("/hello/{name}", (string name)
=> $"Hello {name}!");
app.MapGet("/age", (DateTime birthDate)
=> $"You're about {DateTime.Now.Year - birthDate.Year} years old!");
app.Run();
Sending the following request will throw a BadHttpRequestException
since the required name
parameter is not provided in the route or query string.
curl "http://localhost:5056/hello"
Microsoft.AspNetCore.Http.BadHttpRequestException: Required parameter "string name" was not provided from route or query string.
....
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
Similarly, sending a request to the /age
endpoint with an unparsable birthDate
value will throw an exception.
curl "http://localhost:5056/age?birthDate=invalidDate"
Microsoft.AspNetCore.Http.BadHttpRequestException: Failed to bind parameter "DateTime birthDate" from "invalidDate".
...
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)
ASP.NET Core top-level APIs annotated for trim warnings
To help developers understand which features are incompatible with Native AOT, we’ve annotated the main entry points to subsystems that do not work reliably with Native AOT. When these methods are called from an application with Native AOT enabled, developers will get a warning. For example, the following code snippet will produce a warning at the invocation of AddControllers
to indicate that this API is not trim-safe.
Reduced app size with configurable HTTPS support
In Preview 4, we’ve further reduced Native AOT binary size for apps that don’t need HTTPS or HTTP/3 support. This is quite common for apps that run behind a TLS termination proxy (e.g. hosted on Azure).
When you use the new WebApplication.CreateSlimBuilder
, by default this functionality won’t be included. It can be re-added by calling builder.WebHost.UseKestrelHttpsConfiguration()
or builder.WebHost.UseQuic()
, respectively.
As a result of these and other changes, we can update our table from Preview 3:
We ran a simple ASP.NET Core API app in our benchmarking lab to compare the differences in app size, memory use, startup time, and CPU load, published with and without native AOT:
Publish kind | Startup time (ms) | App size (MB) |
---|---|---|
Default | 169 | 88.5 |
Native AOT – Preview 3 | 34 | 11.3 |
Native AOT – Preview 4 | 32 | 9.3 |
Note the 2 MB drop in app size.
You can explore these and more metrics on our public benchmarks dashboard.
Worker Service template updates
The Worker Service templates in ASP.NET Core (available via dotnet new worker
) now include support for the --aot
flag to enable creating a worker service project with AOT publishing enabled.
dotnet new worker -o WorkerWithAot --aot
The templates have also been updated to leverage the simplified HostApplicationBuilder
for configuring the application host.
using WorkerWithAot;
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<Worker>();
var host = builder.Build();
host.Run();
Additional default services configured in the slim builder
The WebApplication.CreateSlimBuilder
API, introduced in .NET 8 Preview 3, initializes the essential features in an app to minimize its deployed size. In .NET 8 Preview 4, we’ve update the SlimBuilder
to include the following features for an improved development experience, while still maintaining a total app size below 10 MB.
- JSON file configuration for appsettings.json and appsettings.{EnvironmentName}.json
- User secrets configuration
- Console logging
- Logging configuration
API template JSON configuration changes
We introduced the new API project template in .NET 8 Preview 3. In Preview 4, projects created with this template using the --aot
option, have changed to insert the app’s source-generated JsonSerializationContext
into the beginning of the JsonSerializerOptions.TypeInfoResolverChain
. The previously generated code used the now-obsolete JsonSerializerOptions.AddContext<T>
API and any project created with the Preview 3 version of the template should be updated to call the new API.
You can read more about the new JsonSerializerOptions.TypeInfoResolverChain
API in the .NET 8 Preview 4 blog post.
Support for JSON serialization of compiler-generated IAsyncEnumerable<T>
unspeakable types
Support for JSON serialization of IAsyncEnumerable<T>
implementations implemented by the C# compiler is now supported, opening up their use in ASP.NET Core projects configured to publish native AOT. This is useful in scenarios where your route handler returns the result of calling an API that utilizes IAsyncEnumerable<T>
and yield return
to asynchonously return an enumeration, e.g. materializing rows from a database query (example).
You can read more about the JSON serializer support for unspeakable types in the .NET 8 Preview 4 blog post.
Authentication and Authorization
Identity API endpoints
We’re excited to introduce MapIdentityApi<TUser>()
which is an extension method adds two new API endpoints (/register
and /login
). The main goal of the MapIdentityApi
is to make it easy for developers to use ASP.NET Core Identity for authentication in JavaScript-based single page apps (SPA) or Blazor apps. Instead of using the default UI provided by ASP.NET Core Identity, which is based on Razor Pages, MapIdentityApi
adds JSON API endpoints that are more suitable for SPA apps and non-browser apps.
In addition to user registration and login, the identity API endpoints will support features like two-factor authentication and email verification in upcoming previews. You can find a list of planned features in the issues labeled feature-token-identity on the ASP.NET Core GitHub repository.
The following shows the Program.cs
of an ASP.NET Core app that uses MapIdentityApi
to enable both opaque bearer token and cookie authentication. To individually enable cookie or token authentication, you can call the existing AddCookie
or the new AddBearerToken
AuthenticationBuilder
extension methods directly. Both are done for you by the AddIdentityApiEndpoints
method below:
// usings ...
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthorization();
builder.Services.AddDbContext<ApplicationDbContext>(
options => options.UseSqlite(builder.Configuration["ConnectionString"]));
builder.Services.AddIdentityApiEndpoints<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
var app = builder.Build();
app.MapGroup("/identity").MapIdentityApi<IdentityUser>();
app.MapGet("/requires-auth", (ClaimsPrincipal user) => $"Hello, {user.Identity?.Name}!").RequireAuthorization();
app.Run();
// public class ApplicationDbContext : IdentityDbContext<IdentityUser> ...
On the client, you can call the /register
endpoint as follows assuming httpClient
, username
and password
are already initialized in a .NET console app:
// Email confirmation will be added later.
// The request body is: { "username": "<username>", "password": "<password>" }
await httpClient.PostAsJsonAsync("/identity/register", new { username, password });
And you can sign in and get an opaque bearer token using the /login
endpoint:
// 2fa flow will be added later.
// The request body is: { "username": "<username>", "password": "<password>" }
var loginResponse = await httpClient.PostAsJsonAsync("/identity/login", new { username, password });
// loginResponse is similar to the "Access Token Response" defined in the OAuth 2 spec
// {
// "token_type": "Bearer",
// "access_token": "...",
// "expires_in": 3600
// }
// refresh token is likely to be added later
var loginContent = await loginResponse.Content.ReadFromJsonAsync<JsonElement>();
var accessToken = loginContent.GetProperty("access_token").GetString();
httpClient.DefaultRequestHeaders.Authorization = new("Bearer", accessToken);
Console.WriteLine(await httpClient.GetStringAsync("/requires-auth"));
Or, if you want to get a cookie instead, you can set ?cookieMode=true
in the /login
query string:
// HttpClientHandler.UseCookies is true by default on supported platforms.
// The request body is: { "username": "<username>", "password": "<password>" }
await httpClient.PostAsJsonAsync("/identity/login?cookieMode=true", new { username, password });
Console.WriteLine(await httpClient.GetStringAsync("/requires-auth"));
We’re looking forward to getting your feedback on our early work to improve the identity experience for SPA and mobile applications.
Improved support for custom authorization policies with IAuthorizationRequirementData
Prior to this preview, adding a parameterized authorization policy to an endpoint required writing a lot of code.
- Implementing an
AuthorizeAttribute
for each policy - Implementing an
AuthorizationPolicyProvider
to process a custom policy from a string-based contract - Implementing an
AuthorizationRequirement
for the policy - Implementing an
AuthorizationHandler
for each requirement
A partial implementation of a custom parameterized policy is below. The unabbreviated version contains the complete code.
var builder = WebApplication.CreateBuilder();
builder.Services.AddAuthentication().AddJwtBearer();
builder.Services.AddAuthorization();
builder.Services.AddSingleton<IAuthorizationPolicyProvider, MinimumAgePolicyProvider>();
builder.Services.AddSingleton<IAuthorizationHandler, MinimumAgeAuthorizationHandler>();
var app = builder.Build();
app.MapControllers();
app.Run();
[ApiController]
[Route("api/[controller]")]
public class GreetingsController : Controller
{
[MinimumAgeAuthorize(16)]
[HttpGet("hello")]
public string Hello(ClaimsPrincipal user) => $"Hello {(user.Identity?.Name ?? "world")}!";
}
class MinimumAgeAuthorizeAttribute : AuthorizeAttribute { }
class MinimumAgePolicyProvider : IAuthorizationPolicyProvider { }
class MinimumAgeRequirement : IAuthorizationRequirement { }
class MinimumAgeAuthorizationHandler : AuthorizationHandler<MinimumAgeRequirement> { }
This preview introduces the IAuthorizationRequirementData
interface which allows the attribute definition to also specify the requirements associated with the authorization policy. By leveraging this change, we can reimplement our custom authorization policy with fewer lines of code. The unabbreviated version contains the complete code.
var builder = WebApplication.CreateBuilder();
builder.Services.AddAuthentication().AddJwtBearer();
builder.Services.AddAuthorization();
builder.Services.AddSingleton<IAuthorizationHandler, MinimumAgeAuthorizationHandler>();
var app = builder.Build();
app.MapControllers();
app.Run();
[ApiController]
[Route("api/[controller]")]
public class GreetingsController : Controller
{
[MinimumAgeAuthorize(16)]
[HttpGet("hello")]
public string Hello(ClaimsPrincipal user) => $"Hello {(user.Identity?.Name ?? "world")}!";
}
class MinimumAgeAuthorizeAttribute : AuthorizeAttribute, IAuthorizationRequirement, IAuthorizationRequirementData
{
public MinimumAgeAuthorizeAttribute(int age) => Age =age;
public int Age { get; }
public IEnumerable<IAuthorizationRequirement> GetRequirements()
{
yield return this;
}
}
class MinimumAgeAuthorizationHandler : AuthorizationHandler<MinimumAgeAuthorizeAttribute>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MinimumAgeAuthorizeAttribute requirement) { ... }
}
ASP.NET Core metrics
Metrics are measurements reported over time and are most often used to monitor the health of an app and to generate alerts. For example, a counter that reports failed HTTP requests could be displayed in dashboards or generate alerts when failures pass a threshold.
This preview adds new metrics throughout ASP.NET Core using System.Diagnostics.Metrics. Metrics is a modern API for reporting and collecting information about your apps.
Metrics offers a number of improvements compared to existing event counters:
- New kinds of measurements with counters, gauges and histograms
- Powerful reporting with multi-dimensional values
- Integration into the wider cloud native eco-system by aligning with OpenTelemetry standards
Metrics have been added for ASP.NET Core hosting, Kestrel and SignalR. Expect more APIs across .NET to get metrics in the future.
If you’re interested in trying out metrics, we’ve put together Grafana dashboards that report ASP.NET Core metrics collected by Prometheus. You can get the dashboards at the aspnetcore-grafana repository and import them into your own Grafana environment.
Give feedback
We hope you enjoy this preview release of ASP.NET Core in .NET 8. Let us know what you think about these new improvements by filing issues on GitHub.
Thanks for trying out ASP.NET Core!
62 comments
I am so disappointed in the ASP.NET Core team these days. .NET 7/8 is all about Blazor and minimal APIs. Outside of MS I don’t see anybody using any of this.
Blazor is for teams that don’t want to learn a real web-development framework. Angular/React/Vue are the client frameworks for web development. I don’t see any job posts listing Blazor as a desired skill. Web developers are using existing client frameworks like those listed above for client apps and REST APIs (or perhaps GRPC) for server side code. Blazor isn’t viable because nobody is asking for running C# on the client side, there is no benefit. If all you know is C# then maybe but that’s like saying you can use C# in SQL instead of just learning SQL. I really wish the ASP.NET team would stop focusing so much on it and instead provide better support for client-libraries.
You could argue that is what the minimal API is for. But, again, I don’t see it. I’m not replacing controllers with lambdas defined in program startup code. Lambdas themselves were considered bad once local functions were introduced to the language. The happy medium of endpoint routing is really where things are going but my understanding (I haven’t looked since .NET 6) is that endpoint routing via minimal APIs isn’t viable yet because of DI issues and controllers are too much overhead. I think of CQS here. I want to define an endpoint that contains the route URL and code to handle a single request and the program startup doesn’t require any changes. This is what controllers bring today but what minimal APIs seem like they should solve. Maybe I’m missing some cool new .NET 7/8 feature but until .NET 8 is RTM I can’t upgrade anyway. We do not support .NET STS releases because our apps have to run for years without updates. We haven’t even fully migrated all our apps to .NET 6 yet because there isn’t sufficient value add.
Hi Michael. ASP.NET Core attempts to cover pretty much every aspect of web development, so our investments are pretty broad, and our user audience is quite varied. We are investing in Blazor and minimal APIs in part due to larger trends in the web development industry that require a richer frontend development experience and more streamlined backend development. But we’re also investing in many other areas, including new middleware, support for Native AOT, new server protocols, better diagnostics & observability, improved authentication, better integration with JavaScript libraries & tooling, and much more. You can see our full roadmap for .NET 8 at https://aka.ms/aspnet/roadmap. If there are specific issues that you think we should be investing more in, please let us know by opening issues on GitHub and giving a 👍 reaction to the issues you care most about.
i agree with some disagree with others
Microsoft can afford to focus on more than one area they just choose not to for some reason or another
most people outside of microsoft dev eco don’t know and don’t care what microsoft do and blazor not trendy enough for them to ask for just blazor devs like asking for reactjs or angular devs they don’t want to write c# or can’t and don’t care
but for people like me that refuse to write javascript blazor is awesome and i don’t think blazor was made for them in the first place or to replace js spa it was made for people like me backend desktop wpf devs anyway
also about minimal api and top level statement and such i feel like microsoft saw the meme about print hello world in different languages and they draw the line in the sand and said now we need to fix this we are like one line code python now which add now real value it’s not like some new -student- going to see that and choose c# because “it’s one line easy language” he is going to search online and will not find anything that say c# is “easy” because of this
Not everyone wants to use trendy frameworks like React/Angular/Vue and many others that have an expiration date due to the evolving nature of the JavaScript API. I firmly believe that there are thousands of C# developers who want to write C# code on the frontend as well, and this is not a new desire, considering that ASP.NET itself was born for this purpose back in the day. I see that Blazor with WebAssembly is the best opportunity Microsoft has ever had to achieve this. I am very satisfied now, especially with the latest updates of Blazor and what’s to come. They are on the right track now, please don’t stop.
I disagree that Blazor is for teams that don’t want to learn ‘real’ web-development frameworks. I’ve learnt them and have the scars from it. The Javascript ecosystem is a complete mess and has been for over a decade now.
For folks like myself I’m happy Microsoft is investing it’s time and resources in a productive framework that will be supported for years to come without constantly changing or becoming unsupported. I’ve experienced how unproductive teams are with React and Angular and I think anyone who views those as the only options are going to miss out.
I can understand frustration if there’s not sufficient investment in the areas that affect you, but that’s a lot of claims that aren’t backed up by any data.
I imagine Microsoft has a lot of telemetry, as well as feedback from their customers, to drive their decision making.
What makes them “real” frameworks as opposed to Blazor? Yes, Blazor comes with certain downsides (depends on whether you use Blazor Server or Blazor WASM), which need to be considered before using it. But you can build fully functional, large web applications with it.
How do you know that? Full-stack web development has become needlessly complicated once server-side rendered applications with no client-side interactivity became a thing of the past. SO many libraries, tools and languages that we need to learn to get productive. Having a single technology stack and language to cover the frontend and backend needs is a nice change.
But that’s what ORM wrappers are for.. like Entity Framework. It’s already a pretty common practice nowadays. A nice layer of abstraction so we can spend less time dealing with database intricacies. What’s so wrong with having something similar for web development, that takes away the need to build an entire separate stack for the frontend?
You can google for the data to back what I’m saying. For example take a look at the annual Stack Overflow tech survey.
– JS developers – 65%
– C# developers – 28%
– React.js – 43%
– Angular – 20%
– Vue.js – 19%
– ASP.NET Core – 19%
– ASP.NET – 15%
– Angularjs – 9%
– Blazor – 5%
Clearly Blazor isn’t popular and this is from usage around the world. Angularjs which was deprecated a decade ago has twice the usage. ASP.NET (MVC I assume) is 3x. Also, check popular job search sites and see how many companies are looking for Blazor experience vs Angular, React, Vue.js. The usage is very, very clear.
Yes, I understand that if you don’t use a feature then it is frustrating when there are updates. But the ASP.NET team has been overwhelmingly focused on Blazor based upon the posts and code changes to support it. I think there are far more impactful areas to focus on rather than putting so much time into Blazor which does not yet have sufficient demand to warrant it.
Hi Michael. It’s certainly true that there are significantly more JavaScript developers than Blazor developers, or really any other type of developer. This really speaks to the success of the web platform as the world’s most popular software development platform, which for many years only supported running JavaScript. Many of the frameworks listed on the StackOverflow survey have been around for over a decade and originated when JavaScript was the only option in browsers. It’s only recently that new web standards like WebAssembly made running anything else in a browser possible.
We do our best to evolve the .NET platform based on community feedback. We decided to invest in Blazor in part due to the enthusiastic support from the .NET community, and since then Blazor related issues have continued to be some of the most top upvoted (👍) issues in the ASP.NET Core GitHub repo. We released Blazor for the first time a little over three years ago, and it’s now one of the fastest growing parts of the .NET platform. With the new full stack web UI support in .NET 8 we hope that Blazor will prove useful for even more scenarios.
This doesn’t mean we think frontend JavaScript development with .NET isn’t important too. In addition to building and supporting .NET, Microsoft is also heavily invested in the JavaScript ecosystem with TypeScript, NPM, Visual Studio Code, Playwright, React Native for Windows, etc. Many .NET web devs use JavaScript for their web frontends and we expect them to continue to do so. The new ASP.NET Core Identity endpoints in .NET 8 mentioned in this post provide a better authentication story for apps built using frontend JavaScript frameworks, and we continue to invest in our SPA based templates and JavaScript integration and tooling.
There are also lots of other areas in ASP.NET Core that we invest in besides Blazor, including servers, protocols, middleware, APIs, gRPC, SignalR, MVC & Razor Pages, SPA integration, worker services, container integration, diagnostics, security, and performance. Blazor is just one part of a much broader web framework that seeks to provide everything you need to build modern web apps from the frontend to the backend. We’re always looking to make ASP.NET Core better, so if you have ideas on areas that need improvement we of course would love to hear about them. Let us know on GitHub!
You think 5% of devs in the world using certain technology is not popular? Lol…
5% is not nothing and popular is relative term it might be a lot of people but mean nothing in the grand job market
bing is like 3% everybody heard of bing millions use it would you say it’s popular
edge is like 5% almost every windows device have it would you say it’s popular
linux is like 3% on the desktop
5% is the opposite of nothing, it means it is insanely popular, has like a million users and is used in thousands of projects, certainly means you can get a job working with it and means the company that develops it can break even.
Man, I remember a time when it seemed like all job listings wanted Angular, now Blazor is already 1/4 of its adoption. You’re not thinking in perspective. JS frameworks gained popularity only because people were stuck with JS. Now we have Web Assembly and we can write in any language we want, so if you think about the share each language will get in a few years, you can imagine how small each percentage will be. It’s clear WASM is the future, and people actually want to write in whatever language they want. So no, the “real” web is not one where there’s only JS. That is a long gone time (thankfully). We can now write in better-designed languages and we love it. So if you’re actually thinking a few years ahead, and imagining like 50 new different frameworks in 20 programming languages, then the 5% head-start Blazor has seems pretty cool actually. It’s even a big number when compared to Angular or Vue which are only decreasing in popularity, but let’s stop comparing it with JS frameworks. It’s a relatively new framework competing with already old ones (again established in a time when there was no competition and no actual alternatives). But most of all, who cares what it’s share is today, when there are lots of people (including me) who use it since day 1, and wouldn’t even dream of returning to JS. And the number is only growing as people actually using it see how helpful it is right now, not to mention it’s huge potential and lots of cool things coming.
The demand in technology is driven by developers and not by businesses. Businesses simply hire what’s easier to hire. There are more JS devs because the threshold was low to get in and browsers are everywhere. Things can change. Especially if more devs turn away from JS. WASM is a new tech that didn’t get much traction yet and browsers update their spec for it as we speak.
“Blazor is for teams that don’t want to learn a real web-development framework. Angular/React/Vue are the client frameworks for web development. I don’t see any job posts listing Blazor as a desired skill. Web developers are using existing client frameworks like those listed above for client apps and REST APIs (or perhaps GRPC) for server side code. Blazor isn’t viable because nobody is asking for running C# on the client side, there is no benefit.”
Let me express a completely different viewpoint here.
I don’t share the same sentiment. I used AngularJS several years ago, learned React, and even explored the new Angular version. I have utilized them in multiple projects.
Blazor is the preferred choice for me and my team. We have no desire to develop applications with Angular or React; instead, we want to leverage Blazor.
Moreover, I have come across job postings specifically looking for Blazor skills. While the number might not be as high as those for React, I have seen job listings seeking Blazor expertise.
I have been experimenting with Blazor for years, and over the last two years, I have used it extensively on real projects (not just side projects). Given the choice, I would never go back to Angular or React.
I do hope that the ASP.NET team continues to enhance both Blazor Server and Blazor Client, as I thoroughly enjoy developing applications with Blazor.
SQL?
LINQ!
I think dotnet and asp is on the right track: simplifying developer experience and improving performance.
The minimal api is not suitable for all scenarios, but it simplifies many enterprise ones. For example, we have used it a lot in our new microservice codebases along with other dotnet new features since last year.
Blazor has a much bigger story, it’s planned to fill an area that previously was filled by js/jQuery/angular/react… and that’s a potential source of complexity, where two different env needs to talk to each other. Another example is SQL and C#, where EF handles most of the complexity, but frontend lacks such a tool and has been a place that things may begin to become complex, especially if you don’t mind your code structure carefully. And that’s where Blazor is aimed to fill. It needs more time to be adapted by wide range of developers, but if it will become feature rich enough, it will be a bold change.
I am asking them to work on Blazor (though admittedly I find minimal APIs completely useless), and yes, I don’t want to use the popular client frameworks, I’d rather not do programming than work with those full time, I’d rather herd sheep or something. Besides that I don’t know what you want from the ASP.NET team. They don’t own Angular, React and Vue, these libraries have teams that develop them, you should go ask them for features and whatever you need.
I develop with Angular and Svelte, so I think I already know “a real web-development framework”. Svelte is great, but when the decision is on my side, I wouldn’t touch Angular with a ten-feet pole. Sluggish, unnecessarily complicated, full of vulnerabilities, and plagued by a very opinionated design.
Blazor is a gust of fresh air in web side development, and from .NET 6 ahead, is a very mature product. There are enough third-party controls in the market. Is easy to learn, so I can expand my team when I need it. It runs in circles around Angular.
Totally agree. asp.net team spend most time on demo api (eg. minimal API) and toy web UI framework(Blazor).
devs need a way to orginize their rest api and mvc is better than minimal API ,and also need a way for team work instead all the work done by 1 developer.
and for blazor ,
1) blazor server now lack of local state support , so every time it lose connection , the entire page need to be refresh, and that’s not acceptable for a form app,
2) blazor webassembly : the purpose of webassembly is to provide a faster algorithms for javascript for example: video decoding or image manipulate , not for another language to replace javascript . and dynamic object and object proxy is better in javascript than csharp.
that why that blazor is powerfull but not many company touch it.
and for NativeAOT ,
it’s hard to use because now C# and .net is natually in Jit level dynamic(eg. type system and reflection and emit), what if we start by native ,
if we need a type that work for reflaction, then we need put
[ExportType]
or resuse the[Serializeable]
to the class first (also add a assembly level ). replace “emit” with “Generators” or “Metalama” language.Michael, I for one have never been happier with the ASP.NET Core team. I am more productive than I have been at any point over the past 20 years and enjoying architecting new systems with much of their hard work.
Michael Taylor, I couldn’t disagree more. Blazor, with its component model (DRY) and state handling is a revolution in the asp.net development space. I’ve been coding web application (full stack) on many platforms for almost 25 years, and I can say that Blazor is the most innovative platform ASP.NET has seen since webforms (revolutionary for its time).
Perhaps you have some suggestions on where the team should focus efforts? What are your pain points?
To your point, if you are ASP.net developer, IMHO, there has not been a large shift on how you develop since 2008 and MVC. This is not to say there haven’t been substantial improvements (Core, RazorPages, Minimal APIs), but from a web developer’s standpoint, these have all been evolutions of the MVC platform. Blazor, on the other hand, is something completely new and refreshing. It really is a great to build with.
I encourage you to give Blazor a try by building a simple crud app, and I think you will start to see it’s power, elegance, and huge productivity gains. I love MS seems to be returning to the days of building frameworks that empower the developers, so they don’t have to do all the heavy lifting, while at the same time engineering them on the back of ASP.NET, which allows one to modularize and get as low level as needed for their projects. I want to focus on accomplishing my application’s goals and not spend time on low level platform stuff if I don’t have to.
Thank you ASP.NET/Blazor team! Keep rocking on with improvements. So looking forward to Blazor SS rendering in dotnet 8! I also am glad to hear about improvements in Authentication. Not everyone needs the complexity of identity server and “simple” auth is more complicated than it needs to be today.
After 13 years of real web-development, jQuery, AngularJS, React, Vue, Angular 2+, Backbone, Svelte and respective metaframeworks(sveltekit, nextjs, nuxtjs). I’m seriously considering Blazor. With all the new features coming, it seems like a really viable option for a lot of use cases. Real types, good performance, lots of built in stuff.
Great to see these changes coming through in the preview releases.
From speaking to lots of developers I know people find Blazor really productive for building web apps, but are often not so taken with the requirement for an open SignalR connection (and are often building apps where WASM isn’t the preferred option).
The promise of being able to use Blazor’s component model but for server rendered apps opens up a lot of possibilities. Interesting to note similar developments around SSR and client-side rendering hybrid apps happening in React/Svelte circles at the moment as well.
Congrats to the team for getting these features in the previews early on, so they can be battle-tested prior to the official release.
Just a small note, there seems to be some missing code in the post, after this line:
To enable streaming rendering, you’ll first need to add the new Blazor script.
Ah, thanks for catching that. Should be fixed now.
Dear Mr. Daniel
I have an idea why we don’t add .NET framework into browsers like Edge, Chrome or Opera so that we are able to program directly use web client WinForm on .Net Framework library instead.
I know it is possible but right now I see Blazor is doing the same thing but very slow on loading startup page.
Advantage:
Developers doen’t need learn new keywords cause it use .NET library.
WinForm old style for faster developerment web client projects.
With .Net Framework integrated for those browsers so that don’t need to download DLL . It might very good performance when start the web app.
Thank you and regards.
we officially came full circle https://en.wikipedia.org/wiki/Microsoft_Silverlight
Yeah, great idea. We already tried that, it was called Silverlight, it was great and Apple banned it so it died.
Silver light is not already integrated. It must download and install by users. Also SilverLight definition is confused to everyone.
I feel there is a breaking change I’m missing or maybe a bug with the MSBuild because my Blazor WASM project is not building any more. It works fine with preview 3.
Hi George. Thanks for trying the .NET 8 previews out! Please report the problem by opening a GitHub issue at https://github.com/dotnet/aspnetcore/issues/new and we’ll take a look.
Hi Daniel, thanks. It looks like someone else reported it with a reproducible open source example so I’ll monitor the issue. Thanks for the release as well!
To make sure we’re tracking this appropriately, could you please share the link to the corresponding GitHub issue that you’re monitoring?
Sure, it has been transfered to the razor repository at: https://github.com/dotnet/razor/issues/8718
It looks like it affects both .NET 7 and .NET 8 preview
Thanks. This is an unfortunate regression in the updated SDK. We’re working on getting it addressed.
Does Blazor SSR now support event binding, Like click event?
Not yet, but we’re working right now on enabling interactivity right now. It should become available in one of the upcoming .NET 8 previews.
OOB Sass support in Blazor when?
Hi Meshal. We don’t have any immediate plans to enable Sass support directly in Blazor, but we are working on making it easier to integrate a JavaScript based build pipeline into any ASP.NET Core app, including Blazor apps. We should have more to share about that in the months ahead.
When doing server-side web the usual pattern for handling forms is POST > Process > Redirect. Can you show how we do the Redirect part in Blazor and even more interesting how will it work if we want the server blazor form to be replaced on second load by blazor wasm when using auto mode.
Hi Stilgar. Great question! You can redirect using the NavigationManager by calling its NavigateTo method. If this executes during server-side rendering it will become a 302. If the app has already started streaming rendering, then calling NavigateTo will send a special fragment to the browser that tells the Blazor JavaScript code to update location.href.
That’s great, sounds like it is completely transparent, I was scared that I’d had to add ifs and check where the code is running. The streaming rendering support is unexpected bonus
I was also trying to wrap my mind around how it would work. Thanks for the crystal clear explanation! I can’t believe how well thought and seamless this all Blazor “United” already proves to be!
This is awesome, can’t wait to try the new Identity API endpoints!
Anything helping with OAuth2/OIDC in web and in desktop apps as well is greatly appreciated ! MSAL is awful.
Hey – thanks so much for the note. I am a PM on the MSAL team and would be curious to know what the issues are that you ran into with MSAL so that we can continuously improve the library.
Does the Streaming Rendering Demo really demonstrate how it works? Since the behavior is the same as before without Streaming Rendering. The demo works because it will call
StateHasChanged
when meet the first async task duringOnInitializedAsync
You can realize the same effect with .NET7. Please tell me if I’m wrong or provide another demo.Hi Kumima. The big difference with streaming rendering from what you can do today with Blazor is that streaming rendering is based on server-side rendering without the need for a stateful WebSocket connection. The UI experience is handled over a single request/response interaction with the server.
this comment has been deleted.
this comment has been deleted.