Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
C# 13 and .NET 9 – Modern Cross-Platform Development Fundamentals

You're reading from   C# 13 and .NET 9 – Modern Cross-Platform Development Fundamentals Start building websites and services with ASP.NET Core 9, Blazor, and EF Core 9

Arrow left icon
Product type Paperback
Published in Nov 2024
Publisher Packt
ISBN-13 9781835881224
Length 828 pages
Edition 9th Edition
Languages
Arrow right icon
Toc

Table of Contents (18) Chapters Close

Preface 1. Hello, C#! Welcome, .NET! FREE CHAPTER 2. Speaking C# 3. Controlling Flow, Converting Types, and Handling Exceptions 4. Writing, Debugging, and Testing Functions 5. Building Your Own Types with Object-Oriented Programming 6. Implementing Interfaces and Inheriting Classes 7. Packaging and Distributing .NET Types 8. Working with Common .NET Types 9. Working with Files, Streams, and Serialization 10. Working with Data Using Entity Framework Core 11. Querying and Manipulating Data Using LINQ 12. Introducing Modern Web Development Using .NET 13. Building Websites Using ASP.NET Core 14. Building Interactive Web Components Using Blazor 15. Building and Consuming Web Services 16. Epilogue 17. Index

Consuming web services using HTTP clients

Now that we have built and tested our Northwind service, we will learn how to call it from any .NET app using the HttpClient class and its factory.

Understanding HttpClient

The easiest way to consume a web service is to use the HttpClient class. However, many people use it wrongly because it implements IDisposable, and Microsoft’s own documentation shows poor usage of it. See the book links in the GitHub repository for articles with more discussion of this.

Usually, when a type implements IDisposable, you should create it inside a using statement to ensure that it is disposed of as soon as possible. HttpClient is different because it is shared, reentrant, and partially thread-safe.

The problem has to do with how the underlying network sockets must be managed. The bottom line is that you should use a single instance of it for each HTTP endpoint that you consume during the life of your application. This will allow each HttpClient instance to have defaults set that are appropriate for the endpoint it works with while managing the underlying network sockets efficiently.

Configuring HTTP clients

Microsoft is aware of the issue of .NET developers misusing HttpClient, and in ASP.NET Core 2.1, it introduced HttpClientFactory to encourage best practices; that is the technique we will use.

In the following example, we will create a Northwind Blazor WebAssembly standalone project as a client for the Northwind Web API service. Let’s configure an HTTP client:

  1. Use your preferred code editor to open the ModernWeb solution and then add a new project, as defined in the following list:
    • Project template: Blazor WebAssembly Standalone App / blazorwasm
    • Solution file and folder: ModernWeb
    • Project file and folder: Northwind.WebApi.WasmClient
    • Authentication type: None
    • Configure for HTTPS: Selected
    • Progressive Web Application: Cleared
    • Include sample pages: Selected
    • Do not use top-level statements: Cleared
  2. In the Northwind.WebApi.WasmClient.csproj project file, in the package references, remove version attributes.
  3. In the Properties folder, in launchSettings.json, for the https profile, for its applicationUrl, change the random port number for HTTPS to 5152 and for HTTP to 5153, as shown highlighted in the following markup:
    "applicationUrl": "https://localhost:5152;http://localhost:5153",
    
  4. Save changes to all modified files.
  5. In Program.cs, in the call to the AddScoped method, add a statement to enable HttpClientFactory with a named client to make calls to the Northwind Web API service using HTTPS on port 5151 and request JSON as the default response format, as shown in the following code:
    builder.Services.AddScoped(sp => new HttpClient {
      BaseAddress = new Uri("https://localhost:5151/") });
    
  6. In the Northwind.WebApi project, in Program.cs, at the top of the file after the namespace imports, declare a string constant for the name of a CORS policy, as shown in the following code:
    const string corsPolicyName = "allowWasmClient";
    
  7. In Program.cs, before the call to Build, add CORS and configure a policy to allow HTTP calls from clients with different port numbers from the web service itself, as shown in the following code:
    builder.Services.AddCors(options =>
    {
      options.AddPolicy(name: corsPolicyName,
        policy =>
        {
          policy.WithOrigins("https://localhost:5152",
            "http://localhost:5153");
        });
    });
    
  8. In Program.cs, after the call to UseHttpsRedirection, enable CORS with the named policy, as shown in the following code:
    app.UseCors(corsPolicyName);
    

Getting customers as JSON in a Blazor component

We can now create a client page that:

  • Makes a GET request for customers.
  • Deserializes the JSON response using convenient extension methods introduced with .NET 5 in the System.Net.Http.Json assembly and namespace.

Let’s go:

  1. In the Northwind.WebApi.WasmClient.csproj project file, add a reference to the entity models project, as shown in the following markup:
    <ItemGroup>
      <ProjectReference Include=
    "..\Northwind.EntityModels.Sqlite\Northwind.EntityModels.Sqlite.csproj" />
    </ItemGroup>
    
  2. In the Northwind.WebApi.WasmClient project, in _Imports.razor, import the namespace for working with entity models, as shown in the following code:
    @using Northwind.EntityModels @* To use Customer. *@
    
  3. In the Northwind.WebApi.WasmClient project, in the Pages folder, add a new file named Customers.razor.
  4. In Customers.razor, inject the HTTP client service, and use it to call the Northwind Web API service, fetching all customers, and passing them to a table, as shown in the following markup:
    @attribute [StreamRendering]
    @page "/customers/{country?}"
    @inject HttpClient Http
    <h3>
      Customers @(string.IsNullOrWhiteSpace(Country)
        ? "Worldwide" : "in " + Country)
    </h3>
    @if (customers is null)
    {
      <p><em>Loading...</em></p>
    }
    else
    {
      <table class="table">
        <thead>
          <tr>
            <th>Id</th>
            <th>Company Name</th>
            <th>Address</th>
            <th>Phone</th>
            <th></th>
          </tr>
        </thead>
        <tbody>
          @foreach (Customer c in customers)
          {
            <tr>
              <td>@c.CustomerId</td>
              <td>@c.CompanyName</td>
              <td>
                @c.Address<br />
                @c.City<br />
                @c.PostalCode<br />
                @c.Country
              </td>
              <td>@c.Phone</td>
            </tr>
          }
        </tbody>
      </table>
    }
    @code {
      [Parameter]
      public string? Country { get; set; }
      private IEnumerable<Customer>? customers;
      protected override async Task OnParametersSetAsync()
      {
        if (string.IsNullOrWhiteSpace(Country))
        {
          customers = await Http.GetFromJsonAsync
            <Customer[]>("/customers");
        }
        else
        {
          customers = await Http.GetFromJsonAsync
            <Customer[]>($"/customers/in/{Country}");
        }
      }
    }
    
  5. In the Layout folder, in NavMenu.razor, change the Weather menu item to show customers instead, as shown in the following markup:
    <NavLink class="nav-link" href="customers">
      <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Customers
    </NavLink>
    

Starting multiple projects

Up to this point, we have only started one project at a time. Now we have two projects that need to be started, a web service and a Blazor client website. In the step-by-step instructions, I will only tell you to start individual projects one at a time, but you should use whatever technique you prefer to start them.

If you are using Visual Studio

Visual Studio can start multiple projects manually one by one if the debugger is not attached, as described in the following steps:

  1. In Solution Explorer, right-click on the solution or any project and then select Configure Startup Projects…, or select the solution and navigate to Project | Configure Startup Projects….
  2. In the Solution ‘<name>’ Property Pages dialog box, select Current selection.
  3. Click OK.
  4. Select a project in Solution Explorer so that its name becomes bold.
  5. Navigate to Debug | Start Without Debugging or press Ctrl + F5.
  6. Repeat steps 2 and 3 for as many projects as you need.

If you need to debug the projects, then you must start multiple instances of Visual Studio. Each instance can start a single project with debugging.

You can also configure multiple projects to start up at the same time using the following steps:

  1. In Solution Explorer, right-click the solution or any project and then select Configure Startup Projects…, or select the solution and navigate to Project | Configure Startup Projects….
  2. In the Solution ‘<name>’ Property Pages dialog box, select Multiple startup projects, and for any projects that you want to start, select either Start or Start without debugging, as shown in Figure 15.6:

Figure 15.6: Selecting multiple projects to start up in Visual Studio

  1. Click OK.
  2. Navigate to Debug | Start Debugging or Debug | Start Without Debugging or click the equivalent buttons in the toolbar to start all the projects that you selected.

You can learn more about multi-project startup using Visual Studio at the following link: https://learn.microsoft.com/en-us/visualstudio/ide/how-to-set-multiple-startup-projects.

If you are using VS Code

If you need to start multiple projects at the command line with dotnet, then write a script or batch file to execute multiple dotnet run commands, or open multiple command prompt or terminal windows.

If you need to debug multiple projects using VS Code, then after you’ve started the first debug session, you can just launch another session. Once the second session is running, the user interface switches to multi-target mode. For example, in the CALL STACK, you will see both named projects with their own threads, and then the debug toolbar shows a drop-down list of sessions with the active one selected. Alternatively, you can define compound launch configurations in the launch.json.

You can learn more about multi-target debugging using VS Code at the following link: https://code.visualstudio.com/Docs/editor/debugging#_multitarget-debugging.

Starting the web service and Blazor client projects

Now we can try out the web service with the Blazor client calling it:

  1. Start the Northwind.WebApi project and confirm that the web service is listening on ports 5151 and 5150, as shown in the following output:
    info: Microsoft.Hosting.Lifetime[14]
      Now listening on: https://localhost:5151
    info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5150
    
  2. Start the Northwind.WebApi.WasmClient project and confirm that the website is listening on ports 5152 and 5153, as shown in the following output:
    info: Microsoft.Hosting.Lifetime[14]
      Now listening on: https://localhost:5152
    info: Microsoft.Hosting.Lifetime[14]
      Now listening on: http://localhost:5153
    
  3. Start Chrome and navigate to https://localhost:5152/.
  4. On the home page, in the left navigation menu, click Customers, and note the list of customers, as shown in Figure 15.7:

Figure 15.7: Customers worldwide fetched from a web service

  1. In the command prompt or terminal for the web service, note that HTTP logging shows that a successful request was made for customers, as shown in the following output:
    info: Microsoft.EntityFrameworkCore.Database.Command[20101]
          Executed DbCommand (20ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
          SELECT "c"."CustomerId", "c"."Address", "c"."City", "c"."CompanyName", "c"."ContactName", "c"."ContactTitle", "c"."Country", "c"."Fax", "c"."Phone", "c"."PostalCode", "c"."Region"
          FROM "Customers" AS "c"
    info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[2]
          Response:
          StatusCode: 200
          Content-Type: application/json; charset=utf-8
    info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[4]
          ResponseBody: [{"customerId":"ALFKI","companyName":"Alfreds Futterkiste","contactName":"Maria Anders","contactTitle":"Sales Representative","address":"Obere Str. 57","city":"Berlin","region":null,"postalCode":"12209","country":"Germany","phone":"030-0074321","fax":"030-0076545","orders":[]},...
    info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[8]
          Duration: 1039.4409ms
    
  2. In the address bar, change the path to specify a country like Germany, UK, or USA, for example: customers/UK. Press Enter and note the table updates to only show UK customers.
  3. Close Chrome and shut down the two web servers.
lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image