DEV Community

Cover image for .Net 6 WebAPI - Intro to ElasticSearch - Step by Step #aspnetcore
Mohamad Lawand
Mohamad Lawand

Posted on

.Net 6 WebAPI - Intro to ElasticSearch - Step by Step #aspnetcore

In this article we will explore how to utilise Elastic Search into our .Net 6 API.

You can watch the full video on YouTube

Starting Source code:
https://github.com/mohamadlawand087/Net6-ELK

Finished Project
https://github.com/mohamadlawand087/ELS-Dotnet6

DotNet SDK:
https://dotnet.microsoft.com/download

Visual Studio Code:
https://code.visualstudio.com/](https://code.visualstudio.com/

Docker
https://www.docker.com/products/docker-desktop

We will start by adding ELS nuget package

dotnet add package NEST --version 7.17.0
Enter fullscreen mode Exit fullscreen mode

Once our package is installed we can verify it inside our csproj file. The next step is to create our Model which will represent the data which will be using to save in ELS

public class Product
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public int Quantity { get; set; }
    }
Enter fullscreen mode Exit fullscreen mode

Then we need to update our configuration, inside our appsettings.json we need to change it to the following

{
  "Serilog": {
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Microsoft": "Information",
        "System": "Warning"
      }
    }
  },
  "ELKConfiguration": {
    "Uri": "http://localhost:9200",
    "index": "products",
  },
  "AllowedHosts": "*"
}
Enter fullscreen mode Exit fullscreen mode

Inside the root folder of our application, create a new folder called extensions. Then create a class called ElasticSearchExtensions which is our ELS extension method which will be used to initialise ELS when our application starts

public static class ElasticSearchExtensions
    {
        public static void AddElasticsearch(
            this IServiceCollection services, IConfiguration configuration)
        {
            var url = configuration["ELKConfiguration:url"];
            var defaultIndex = configuration["ELKConfiguration:index"];

            var settings = new ConnectionSettings(new Uri(url)).BasicAuthentication(userName, pass)
                .PrettyJson()
                .DefaultIndex(defaultIndex);

            AddDefaultMappings(settings);

            var client = new ElasticClient(settings);

            services.AddSingleton<IElasticClient>(client);

            CreateIndex(client, defaultIndex);
        }

        private static void AddDefaultMappings(ConnectionSettings settings)
        {
            settings
                .DefaultMappingFor<Product>(m => m
                    .Ignore(p => p.Price)
                    .Ignore(p => p.Measurement)
                );
        }

        private static void CreateIndex(IElasticClient client, string indexName)
        {
            var createIndexResponse = client.Indices.Create(indexName,
                index => index.Map<Product>(x => x.AutoMap())
            );
        }
    }
Enter fullscreen mode Exit fullscreen mode

Now that our extension method has been added, its time to add it to our program.cs so it will be injected into our application startup

builder.Services.AddElasticsearch(builder.Configuration);
Enter fullscreen mode Exit fullscreen mode

Now that our application knows about ELS we need to create our controller ProductsController so we can interact with our ELS.

public class ProductsController : ControllerBase
{
    private readonly IElasticClient _elasticClient;
    private readonly ILogger<ProductsController> _logger;

    public ProductsController(
                        IElasticClient elasticClient,
                        ILogger<ProductsController> logger)
    {
        _logger = logger;
        _elasticClient = elasticClient;
    }

    [HttpGet(Name = "GetAllProducts")]
    public async Task<IActionResult> Get(string keyword)
    {
       var result = await _elasticClient.SearchAsync<Product>(
                        s => s.Query(
                            q => q.QueryString(
                                d => d.Query('*' + keyword + '*')
                            )).Size(5000));

        _logger.LogInformation("ProductsController Get - ", DateTime.UtcNow);
       return Ok(result.Documents.ToList());
    }

    [HttpPost(Name = "AddProduct")]
    public async Task<IActionResult> Post(Product product)
    {
        // Add product to ELS index
        var product1 = new Product 
        {
            Description = "Product 1",
            Id = 1,
            Price = 200,
            Measurement = "2",
            Quantity = 90,
            ShowPrice = true,
            Title = "Nike Shoes",
            Unit = "10"
        };

        // Index product dto
        await _elasticClient.IndexDocumentAsync(product);

        _logger.LogInformation("ProductsController Get - ", DateTime.UtcNow);
       return Ok();
    }
}
Enter fullscreen mode Exit fullscreen mode

Please add your question below and follow me here and subscribe to my YouTube Channel.

Top comments (3)

Collapse
 
bacclunky profile image
BacClunky

Hi Mohamad,

Do you have any issue with localhost:9200? I dont have http for my setup. I could not make it work.

I got this issue, even I tried the solution github.com/elastic/elasticsearch-n...

Invalid NEST response built from a unsuccessful () low level call on PUT: /platforms/_doc/1

Audit trail of this API call:

  • [1] ProductCheckOnStartup: Took: 00:00:00.0808152
  • [2] ProductCheckFailure: Node: localhost:9200/ Took: 00:00:00.0787094 # OriginalException: Elasticsearch.Net.ElasticsearchClientException: The client is unable to verify that the server is Elasticsearch due to an unsuccessful product check call. Some functionality may not be compatible if the server is running an unsupported product. Call: Status code unknown from: GET / ---> Elasticsearch.Net.PipelineException: The client is unable to verify that the server is Elasticsearch due to an unsuccessful product check call. Some functionality may not be compatible if the server is running an unsupported product. ---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception. ---> System.Security.Authentication.AuthenticationException: The remote certificate was rejected by the provided RemoteCertificateValidationCallback. at System.Net.Security.SslStream.SendAuthResetSignal(ProtocolToken message, ExceptionDispatchInfo exception) at System.Net.Security.SslStream.ForceAuthenticationAsyncTIOAdapter at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Boolean async, Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken) --- End of inner exception stack trace --- at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Boolean async, Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken) at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at System.Net.Http.HttpClient.SendAsyncCore(HttpRequestMessage request, HttpCompletionOption completionOption, Boolean async, Boolean emitTelemetryStartStop, CancellationToken cancellationToken) at Elasticsearch.Net.HttpConnection.RequestAsyncTResponse --- End of inner exception stack trace --- at Elasticsearch.Net.RequestPipeline.ThrowIfTransientProductCheckFailure() at Elasticsearch.Net.RequestPipeline.PingAsync(Node node, CancellationToken cancellationToken) at Elasticsearch.Net.Transport1.PingAsync(IRequestPipeline pipeline, Node node, CancellationToken cancellationToken) at Elasticsearch.Net.Transport1.RequestAsyncTResponse --- End of inner exception stack trace --- # Request: # Response:
Collapse
 
corujasdevbr profile image
Fernando Henrique

Great article, good job!!!

In line _logger.LogInformation("ProductsController Get - ", DateTime.UtcNow) alter to _logger.LogInformation("ProductsController Post - ", DateTime.UtcNow);

Have a nice week

Collapse
 
nphamvn profile image
nphamvn

in real application how should we index the document? And how to index for existing data?