Blazor is an experimental web UI framework based on C#, Razor, and HTML that runs in the browser via WebAssembly. Blazor promises to greatly simplify the task of building fast and beautiful single-page applications that run in any browser. It does this by enabling developers to write .NET-based web apps that run client-side in web browsers using open web standards.
If you already use .NET, this completes the picture: you’ll be able to use your skills for browser-based development in addition to existing scenarios for server and cloud-based services, native mobile/desktop apps, and games. If you don’t yet use .NET, our hope is that the productivity and simplicity benefits of Blazor will be compelling enough that you will try it.
Web development has improved in many ways over the years but building modern web applications still poses challenges. Using .NET in the browser offers many advantages that can help make web development easier and more productive:
- Stable and consistent: .NET offers standard APIs, tools, and build infrastructure across all .NET platforms that are stable, feature rich, and easy to use.
- Modern innovative languages: .NET languages like C# and F# make programming a joy and keep getting better with innovative new language features.
- Industry leading tools: The Visual Studio product family provides a great .NET development experience on Windows, Linux, and macOS.
- Fast and scalable: .NET has a long history of performance, reliability, and security for web development on the server. Using .NET as a full-stack solution makes it easier to build fast, reliable and secure applications.
Running .NET and C# in the browser is made possible by WebAssembly, a new web standard for a “portable, size- and load-time-efficient format suitable for compilation to the web.” WebAssembly enables fundamentally new ways to write web apps. Code compiled to WebAssembly can run in any browser at native speeds. Blazor runs on a WebAssembly based implementation of .NET. No plugins or transpilation needed.
Blazor apps are built out of components. Components are reusable pieces of web UI that handle events and maintain state. Blazor components are implemented using a combination of C# and HTML markup. At build-time your Blazor components are compiled into .NET classes that get downloaded into the browser as normal .NET assemblies (.dll).
When your app gets executed the components render their contents into a rendering tree that is used to update the browser DOM. Each time an event occurs on a component (ex in response to user interaction), that component regenerates its render tree. Blazor will then compare the new render tree against the previous one and apply any modifications to the browser DOM.
Let's get started!
To create your first project from Visual Studio:
-
Select File -> New -> Project -> Web -> ASP.NET Core Web Application and click OK.
-
The "New ASP.NET Core Web Application" dialog will appear. Make sure .NET Core and ASP.NET Core 2.0 are selected at the top. Pick the Blazor template and click OK.
-
Once the project is created, press Ctrl-F5 to run the app without the debugger. Running with the debugger (F5) is not supported at this time, but is coming soon.
Note: If you're not using Visual Studio you can install and use the Blazor templates from the command-line on your OS of choice (Windows, macOS, Linux):
dotnet new -i Microsoft.AspNetCore.Blazor.Templates
dotnet new blazor -o BlazorApp1
cd BlazorApp1
dotnet run
You should now be able to see your Blazor app running in the browser.
Now let's take a look at how you build web UI components with Blazor.
-
Browse to each of the app's three pages: Home, Counter, Fetch data.
These three pages are implemented by the three Razor files in the
Pages
folder:Index.cshtml
,Counter.cshtml
,FetchData.cshtml
. Expand thePages
folder in the Solution explorer to see these files. Each of these files implements a Blazor component that will get compiled and executed client-side in the browser. -
Try clicking the button on the Counter page.
Each click increments the counter without a page refresh. Normally this kind of client-side behavior would be handled in JavaScript, but here it's implemented in C# and .NET by the
Counter
component. -
Take a look at the implementation of the
Counter
component in theCounter.cshtml
file:@page "/counter" <h1>Counter</h1> <p>Current count: @currentCount</p> <button @onclick(IncrementCount)>Click me</button> @functions { int currentCount = 0; void IncrementCount() { currentCount++; } }
The UI for the
Counter
component is defined using normal HTML. Dynamic rendering logic (loops, conditionals, expressions, etc.) is added using an embedded C# syntax called Razor. The HTML markup and C# rendering logic are converted into a component class at build time. The name of the generated .NET class matches the name of the file.Members of the component class are defined in a
@functions
block. In the@functions
block you can specify component state (properties, fields) as well as methods for event handling or for defining other component logic. These members can then be used as part of the component's rendering logic and for handling events.When the button is clicked the counter component's registered
onclick
handler is called (theIncrementCount
method) and theCounter
component regenerates its render tree. Blazor will then compare the new render tree against the previous one and apply any modifications to the browser DOM. In the case of the counter component the displayed count gets updated. -
Update the markup for the
Counter
component to make the top level header more exciting!!.@page "/counter" <h1><em>Counter!!</em></h1>
-
Also modify the C# logic of the Counter component to make the count increment by two instead of one.
@functions { int currentCount = 0; void IncrementCount() { currentCount += 2; } }
-
Build and rerun the app by from within Visual Studio by pressing
Ctrl-F5
to see the changes (live reload support coming soon).
Once you define a component it can be used to implement other components. The markup for using a component looks like an HTML tag where the name of the tag is the component type.
-
Add a
Counter
component to the home page of the app, like this:@page "/" <h1>Hello, world!</h1> Welcome to your new app. <SurveyPrompt Title="How is Blazor working for you?" /> <Counter />
-
Build and run the app (Ctrl-F5). You should now see a separate instance of the
Counter
component on the home page.
Components can also have parameters, which you define using public properties on the component class. Use attributes to specify arguments for a component in markup.
-
Update the
Counter
component to have anIncrementAmount
property that defaults to 1, but that we can change to something different.@functions { int currentCount = 0; public int IncrementAmount { get; set; } = 1; void IncrementCount() { currentCount += IncrementAmount; } }
-
On the home page change the increment amount for the
Counter
to 10.<Counter IncrementAmount="10" />
-
Build and run the app (Ctrl-F5)
The counter on the home page now increments by 10, while the counter page still increments by 1.
The @page
directive at the top of the Counter.cshtml
file specifies that this component is a page to which requests can be routed. Specifically, the Counter
component will handle requests sent to /counter
. Without the @page
directive the component would not handle any routed request, but it could still be used by other components.
Services registered with the app's service provider are available to components via dependency injection. You can inject services into a component using the @inject
directive.
Take a look at the implementation of the FetchData
component in FetchData.cshtml
. The @inject directive is used to inject an HttpClient
instance into the component.
@page "/fetchdata"
@inject HttpClient Http
The FetchData
component uses the injected HttpClient
to retrieve some JSON from the server when the component is initialized. Under the covers the HttpClient
provided by the Blazor runtime is implemented using JavaScript interop to call the underlying browser fetch API to send the request (it is possible from C# to call any JavaScript library or browser API). The retrieved data is deserialized into the forecasts
C# variable as an array of WeatherForecast
objects.
@functions {
WeatherForecast[] forecasts;
protected override async Task OnInitAsync()
{
forecasts = await Http.GetJsonAsync<WeatherForecast[]>("/sample-data/weather.json");
}
class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF { get; set; }
public string Summary { get; set; }
}
}
A @foreach
loop is then used to render each forecast instance as a row in the weather table.
<table class='table'>
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
Let's add a new page to our app that implements a simple todo list.
-
Add a
Todo
page to the app by right-clicking on thePages
folder and selecting Add -> New item -> Razor View. Name the fileTodo.cshtml
and click OK. -
Replace the content of the
Todo.cshtml
file with some initial markup.@page "/todo" <h1>Todo</h1>
-
Add the todo list page to the nav bar by updating
Shared/NavMenu.cshtml
to add a nav link for the todo list. Add the following list item markup below the existing ones.<li> <NavLink href="/todo"> <span class='glyphicon glyphicon-th-list'></span> Todo </NavLink> </li>
-
Build and run the app. You should now see the new todo page.
-
Add a class to represent your todo items by right-clicking on the project and selecting Add -> Class. Name the file
TodoItem.cs
and click OK. -
Replace the class definition in
TodoItem.cs
with the following class.public class TodoItem { public string Title { get; set; } public bool IsDone { get; set; } }
-
Now go back to the
Todo
component inTodo.cshtml
and add a field for the todos in a@functions
block. TheTodo
component will use this field to maintain the state of the todo list.@functions { IList<TodoItem> todos = new List<TodoItem>(); }
-
Add some list markup and a
foreach
loop to render each todo item as a list item.@page "/todo" <h1>Todo</h1> <ul> @foreach (var todo in todos) { <li>@todo.Title</li> } </ul>
-
Now we need some UI for adding todos to the list. Add a text input and a button at the bottom of the list.
@page "/todo" <h1>Todo</h1> <ul> @foreach (var todo in todos) { <li>@todo.Title</li> } </ul> <input placeholder="Something todo" /> <button>Add todo</button> @functions { IList<TodoItem> todos = new List<TodoItem>(); }
-
Build and run the app (Ctrl-F5)
Nothing happens yet when we click the "Add todo" button, because we haven't wired up an event handler.
-
Add an
AddTodo
method to theTodo
component and register it for button clicks using the@onclick
attribute.<input placeholder="Something todo" /> <button @onclick(AddTodo)>Add todo</button> @functions { IList<TodoItem> todos = new List<TodoItem>(); void AddTodo() { // Todo: Add the todo } }
The
AddTodo
C# method will now get called every time the button is clicked. -
To get the title of the new todo item add a
newTodo
string field and bind it to the value of the text input using the@bind
attribute.IList<TodoItem> todos = new List<TodoItem>(); string newTodo;
<input placeholder="Something todo" @bind(newTodo) />
-
We can now update the
AddTodo
method to add theTodoItem
with the specified title to the list. Don't forget to clear the value of the text input by settingnewTodo
to an empty string.@page "/todo" <h1>Todo</h1> <ul> @foreach (var todo in todos) { <li>@todo.Title</li> } </ul> <input placeholder="Something todo" @bind(newTodo) /> <button @onclick(AddTodo)>Add todo</button> @functions { IList<TodoItem> todos = new List<TodoItem>(); string newTodo; void AddTodo() { if (!String.IsNullOrWhiteSpace(newTodo)) { todos.Add(new TodoItem { Title = newTodo }); newTodo = ""; } } }
-
Build and run the app (Ctrl-F5). Try adding some todos to your todo list.
-
Lastly, what's a todo list without check boxes? And while we're at it we can make the title text for each todo item editable as well. Add a checkbox input and text input for each todo item and bind their values to the
Title
andIsDone
properties respectively.<ul> @foreach (var todo in todos) { <li> <input type="checkbox" @bind(todo.IsDone) /> <input @bind(todo.Title) /> </li> } </ul>
-
To verify that these values are being bound, update the
h1
header to show a count of the number of todo items that are not yet done.<h1>Todo (@todos.Where(todo => !todo.IsDone).Count())</h1>
-
Your completed
Todo
component should look like this:@page "/todo" <h1>Todo (@todos.Where(todo => !todo.IsDone).Count())</h1> <ul> @foreach (var todo in todos) { <li> <input type="checkbox" @bind(todo.IsDone) /> <input @bind(todo.Title) /> </li> } </ul> <input placeholder="Something todo" @bind(newTodo) /> <button @onclick(AddTodo)>Add todo</button> @functions { IList<TodoItem> todos = new List<TodoItem>(); string newTodo; void AddTodo() { if (!String.IsNullOrWhiteSpace(newTodo)) { todos.Add(new TodoItem { Title = newTodo }); newTodo = ""; } } }
Build and run the app and try adding some todo items.
Now let's publish our Blazor app to Azure.
-
Right click on the project and select Publish.
-
In the "Pick a publish target" dialog select "App Service" and "Create New", then click Publish.
-
In the "Create App Service" dialog pick a name for the application and select the subscription, resource group, and hosting plan that you want to use. Click "Create" to create the app service and publish the app.
Wait a minute or so for the app to be deployed.
Your app should now be running in Azure.
You can mark that todo item to build your first Blazor app as done. Nice job!
For a more involved Blazor sample app check out the Flight Finder sample on GitHub.
This is the first preview release of Blazor. Already you can get started building component-based web apps that run in the browser with .NET. We invite you to try out Blazor today and let us know what you think about the experience so far. Check out https://aka.ms/install-blazor to get started. You can file issues on Github, take our in-product survey, and chat with us on Gitter. But this is just the beginning! We have many new features and improvements planned for future updates. We hope you enjoy trying out this initial release and we look forward to sharing new improvements with you in the near future.