Friday, December 11, 2020

HttpRepl essentials

HttpRepl is a light-weight utility from Microsoft used to test REST APIs and view their results. It can run on any O/S that .NET Core (or .NET 5 and later) runs on. HttpRepl is an open-source project on GitHub at https://github.com/dotnet/HttpRepl. It is an alternative to Postman.

Companion video: https://youtu.be/RLdnXN4OAPg

To install the HttpRepl, run the following command from within a terminal window:

dotnet tool install -g Microsoft.dotnet-httprepl

To update HttpRepl to the latest version, enter the following command:

dotnet tool update -g Microsoft.dotnet-httprepl

On Windows, this tool gets installed at:

%USERPROFILE%\.dotnet\tools\httprepl.exe

Let us test  HttpRepl with a REST API service located at https://api4all.azurewebsites.net. From within a terminal window, enter the following command:

httprepl https://api4all.azurewebsites.net

HttpRepl

You are advised to associate the HttpRepl utility with a text editor so that you can compose your POST & PUT requests. The below terminal window command will associate Notepad.exe (in Windows) with HttpRepl:

pref set editor.command.default "C:\Windows\system32\notepad.exe"

pref set editor.command.default

Enter dir (or ls) :

HttpRepl allows you to navigate through your API tree. In our current service, all services are under /api. Therefore, change directory to api then check the contents with:

cd api
dir
dir

Now, let’s checkout Students. Therefore, change to the Students location and inspect what is available there with:

cd Students
dir

dir

NOTE: HttpRepl is case-sensitive. This means that “cd students” will generate an error.

This shows us that we can do GET, POST, PUT and DELETE. Entering the id is necessary for DELETE, PUT and retrieving one Student (GET by id).

Let us retrieve all Students data by entering GET:

GET

How about we try POST. Just enter POST and the editor we configured earlier on pops up with a JSON template:
POST

Enter some data then simply save & close your editor. I entered the following then saved & closed the editor. 
POST

This was the output I got:

POST
Enter GET to ensure that data was indeed inserted:
GET

Let’s do a GET by id by entering the following:

GET A00555555

This is the result:
GET by id

How about we do an update. Enter:

PUT A00555555

This opens the editor again. However, the existing data is not displayed. This is what I got:
PUT

I entered data as follows, using the same ID as before, and changing only school to nursing. I then saved the document before closing it:


PUT

This is the output I received:

PUT result

I then did a GET to see all students:

GET all result

Finally, let us delete our student by entering:

DELETE A00555555

You should see the following response:

DELETE by id

Now when we do a GET, there will be no student with ID = A00555555:
GET all

To exit out of HttpRepl, simply type exit.

I hope you found HttpRepl a useful utility.





Use Service Reference in Visual Studio 2019 to consume a REST API with OpenAPI description from a C# console app

In this tutorial I will show you how easy it is to consume a REST API Service using the ‘Service Reference …’ feature in Visual Studio 2019. I will consume a simple service located at https://api4all.azurewebsites.net/

Companion video: https://youtu.be/XqIniGHpcEc

Source Code: https://github.com/medhatelmasry/ConsumeOpenAPI.git

Prerequisites:

  1. You need to have Visual Studio 2019 installed on your Windows computer. In my case, I am using: Microsoft Visual Studio Community 2019 Version 16.8.2
  2. The REST API you are consuming needs to have an OpenAPI programming language-agnostic interface description for REST APIs.
Point your browser to https://api4all.azurewebsites.net/. The landing page is an OpenAPI page that has the following heading:

OpenAPI Endpoint







Copy the link to the swagger.json file in the top-left corner and park it in Notepad.exe for later use.

Let us create a simple “Console App (.NET Core)” application in Visual Studio 2019 to consume the REST API service.
Console App (.NET Core)

Once your console app is created, Add >> Service Reference …

Add >> Service Reference
Choose OpenAPI, then click Next.
OpenAPI

Select URL then paste into the textbox the link to the swagger.json file that you parked in Notepad.exe. Click on Finish.
OpenAPI URL

A "Service reference configuration progress" dialog will appear. Click Close when it is done.
Service reference configuration progress

Looking at "Solution Explorer", you will find a folder named OpenAPI with swagger.json contained inside it.
swagger.json


Build (or compile) your application so that the proxy class that gets created is visible in your application's environment.

If you open your obj folder in File Explorer, you will find that a proxy class named swaggerClient.cs was auto-magically created for you.
swaggerClient.cs

Feel free to open this file in a text editor to have a peek at its contents. Alternatively, you can click on ... in your Service Dependencies dialog and select "View generated code".
View generated code


These are the CRUD methods that are provided  by the swaggerClient object:

Method nameHTTP VerbPurpose
StudentsAllAsyncGETretrieve all students
Students2AsyncGETget student by id
StudentsAsyncPOSTadd a student
Students3AsyncPUTupdate student data
Students4AsyncDELETEdelete student by id

It is obvious that the swaggerClient method names are not very intuitive. The above table will help you figure out the translation.

Add the following instance variable, that represents the BASE_URL, to the Program.cs class:

const string BASE_URL = "https://api4all.azurewebsites.net";

Add the following displayStudents() method to Program.cs:

private static async Task displayStudents() {
  using (var httpClient = new HttpClient()) {
    var client = new swaggerClient(BASE_URL, httpClient);
    var items = await client.StudentsAllAsync();
    foreach (var i in items) {
      Console.WriteLine($"{i.StudentId}\t{i.FirstName}\t{i.LastName}\t{i.School}");
    }
  }
}

Replace your Main() method in Program.cs with the following code:

static async Task Main(string[] args) {
   await displayStudents();
}

OpenAPI output

Below are the other methods that complete all other CRUD operations:

private static async Task getStudentById(string id) {
  using (var httpClient = new HttpClient()) {
    var client = new swaggerClient(BASE_URL, httpClient);
    var item = await client.Students2Async(id);
    Console.WriteLine($"{item.StudentId}\t{item.FirstName}\t{item.LastName}\t{item.School}");
  }
}

private static async Task addStudent() {
  using (var httpClient = new HttpClient()) {
    var client = new swaggerClient(BASE_URL, httpClient);
    var student = new Student() {
        StudentId = "A00777776",
        FirstName = "Joe",
        LastName = "Roy",
        School = "Forestry"
    };

    try {
      var response = await client.StudentsAsync(student);
    } catch (ApiException apiEx) {
      // not really error because server returns HTTP Status Code 201
      Console.WriteLine(apiEx.ToString());
    }
  }
}

private static async Task updateStudentById(string id) {
  using (var httpClient = new HttpClient()) {
    var client = new swaggerClient(BASE_URL, httpClient);
    var student = new Student() {
        StudentId = id,
        FirstName = "Pam",
        LastName = "Day",
        School = "Nursing"
    };
    await client.Students3Async(id, student);
  }
}

private static async Task deleteStudentById(string id) {
    using (var httpClient = new HttpClient()) {
      var client = new swaggerClient(BASE_URL, httpClient);
      var item = await client.Students4Async(id);
    }
}

I hope you appreciate how easy and painless it is to consume an OpenAPI REST service using Visual Studio 2019.

Thursday, August 13, 2020

Deploying an ASP.NET Core application that uses LocalDB to IIS on Windows 10

 LocalDB is intended as a light-weigh development version SQL Server and is not supposed to be used in production.  Similarly, it is not the best version of SQL Server to be used with a web app hosted on IIS. 

Having said that, there are circumstances when a developer may wish to run an ASP.NET Core web app that works with LocalDB on IIS. This post explains one way I got this to work. 

Assumptions: It is assumed the following is running on your Windows 10 computer:

  • git
  • Visual Studio 2019 (or later)
  • LocalDB
  • .NET Core 3.1
  •  dotnet-ef tool 
  • Internet Information Services (IIS)

In this tutorial we will deploy an ASP.NET 3.1 Web API application that uses LocalDB to IIS . As a starting point, you can clone a simple ASP.NET Core 3.1 web application from https://github.com/medhatelmasry/SchoolAPI-3.1.git.

To clone the above application, go to a suitable working directory in a terminal window and run the following command:

git clone https://github.com/medhatelmasry/SchoolAPI-3.1.git

You can then go into the newly created SchoolAPI-3.1 directory with:

cd SchoolAPI-3.1

Let us quickly test this application to make sure that it works. Type the following in a terminal window:

dotnet-ef database update

dotnet run

You should see the following when you point your browser to http://localhost:5000/api/students:

Hit CTRL C to stop the server.

There is a solution (.sln) file in the root directory of the web app. Open this solution in Visual Studio 2019. This can easily be done by typing the following in the terminal window:

SchoolAPI.sln

Once in Visual Studio, edit the appsettings.json file and have a peek at the connection string, which looks like this:

"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=School;Trusted_Connection=True;MultipleActiveResultSets=true"

We will need to do a minor change to this connection string to make it work when our web app is hosted by IIS.

Since we are in Visual Studio 2019, let us run the web application by hitting CTRL F5. We should see the same result as we saw previously when we started the app from a terminal window. 

Install ASP.NET Core Hosting Bundle

For IIS to support ASP.NET Core, you will need to install the “ASP.NET Core Hosting Bundle”. Point your browser to https://dotnet.microsoft.com/download/dotnet-core/3.1. Click on the “Hosting Bundle” link.


A file named dotnet-hosting-3.1.6-win.exe gets downloaded to your computer. Go ahead and run this installer.

Publish web app to IIS

Let us now publish our application to IIS. Create a folder named SchoolAPI under c:\inetpub\wwwroot, which is the the root directory of IIS. 

Back in Visual Studio, right click on the SchoolAPI node in Solution Explorer and select Publish...

On the Publish dialog, select Folder, then click Next.

Use the Browse... button to select the c:\inetpub\wwwroot/SchoolAPI directory, then click on Finish.

 

Click on Publish.

Let us create a website in IIS. Start "Internet Information Services (IIS) Manager". Right-click on the Sites node then select "Add Website..."



Add a website as shown below.


Select the "Application Pools" node then double-click on the SchoolAPI pool in the center.

Select "No Managed Code" in the ".NET CLR version" selection list, then click OK.

Point your browser to http://localhost:8088/api/students. The web application will fail with an HTTP ERROR 500. Unfortunately, there is not enough information to tell us what the problem is. I will describe to you two simple ways of finding out what the problem is:

1) Start the Windows "Event Viewer". Select "Windows Logs" >> Application, then read the first couple of errors.


You will come across this error, which suggests that the app is unable to connect to SQL Server:

A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. 

2) To see a more descriptive error message in your browser, you can also set the environment variable ASPNETCORE_ENVIRONMENT to Development. Add this to the C:\inetpub\wwwroot\SchoolAPI\web.config file inside the <aspNetCore … > section. Once you do so, your < aspNetCore…> block will look like this:

<aspNetCore processPath="dotnet" arguments=".\SchoolAPI.dll" 

  stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" hostingModel="inprocess" >

  <environmentVariables>

    <environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Development" />

  </environmentVariables>

</aspNetCore>

Save the web.config file, then refresh the page in your browser. A more detailed error message will display.

One way to fix the database connectivity problem

I have one solution to this problem so that IIS can communicate with LocalDB. I welcome any other suggestions. 

From within a terminal window, execute the following commands:

sqllocaldb start MSSQLLocalDB
sqllocaldb info MSSQLLocalDB

You should experience output similar to the following:

C:\>sqllocaldb start MSSQLLocalDB
LocalDB instance "mssqllocaldb" started.

C:\>sqllocaldb info MSSQLLocalDB
Name:               mssqllocaldb
Version:            13.1.4001.0
Shared name:
Owner:              bingo
Auto-create:        Yes
State:              Running
Last start time:    2020-08-13 11:33:00 AM
Instance pipe name: np:\\.\pipe\LOCALDB#1961D8A7\tsql\query

We can use the "Instance pipe name" as the name of the server in the database connection string. Copy the value of the "Instance pipe name" without 'np:'. In the above example it would be '\\.\pipe\LOCALDB#1961D8A7\tsql\query'. Go to Visual Studio 2019, open appsettings.json and paste contents of your clipboard instead of '(localdb)\\mssqllocaldb' in the connection string. In my case, the connection string looked like this:

"DefaultConnection": "Server=\\\\.\\pipe\\LOCALDB#1961D8A7\\tsql\\query;Database=School;Trusted_Connection=True;MultipleActiveResultSets=true"

NOTE: When you pasted the name pipe, all \ are escaped to \\. This is OK and do not be alarmed.

If you run the web application in Visual Studio, it should be working as expected:

Now, let us do the same change to C:\inetpub\wwwroot\SchoolAPI\appsettings.json. You can simply replace the connection string in C:\inetpub\wwwroot\SchoolAPI\appsettings.json with the connection string from appsettings.json in Visual Studio 2019.

Thereafter, point your browser to http://localhost:8088/api/students. This time, we will get a different error:

SqlException: Login failed for user 'IIS APPPOOL\SchoolAPI'.

This error suggests that, although the database was found, IIS failed to login to the database using account 'IIS APPPOOL\SchoolAPI'. To fix this problem, we will get IIS to use a different account. Select the SchoolAPI application pool, then click on 'Advanced Settings..." on the right-side.


Click on the ... beside Identity.


Change the "Built-in account:" to LocalSystem, then click on OK followed by OK again.
By changing the account to LocalSystem, IIS will try and login to our database using a built-in account named 'NT AUTHORITY\SYSTEM'. We need to give this account access to our School database in LocalDB. 

Download and install SQL Server Management Studio (SSMS) from https://docs.microsoft.com/en-us/sql/ssms/download-sql-server-management-studio-ssms.

Start SSMS. Use "Windows Authentication" to login into server name "(localdb)\MSSQLLocalDB".


Right-click on Security >> Logins and select "New Login...".
Click on Search...

Enter 'system'.

Click on "Check Names". When the account is found, you will see SYSTEM in uppercase and underlined.

Click on OK. Next, select the "User Mapping" node on the left side, check the School database, then check db_owner at the bottom.


Click on OK to close the Login - New dialog.

Browser to http://localhost:8088/api/students. The page should display data as expected.

NOTE: If you receive an error suggesting that the database cannot be found, then run these command again in a terminal window and update the "Instance pipe name" in the appsettings.json connection string.

sqllocaldb start MSSQLLocalDB
sqllocaldb info MSSQLLocalDB

As I said before, this is really an academic exercise and that LocalDB should never be used in production. SQL Express is a much better option.