Using Elasticsearch with ASP.NET Core 1.0

This article shows how to use Elasticsearch with ASP.NET Core 1.0, dnxcore or dnx451. ElasticsearchCrud ASP.NET Core 1.0 RTM version is used for the Elasticsearch data access. ElasticsearchCrud supports netcoreapp1.0 and .NET with Elasticsearch 2.3.1. By supporting dnxcore50, the Elasticsearch API can now be run on windows, linux or a mac.

2016.06.30: Updated to ASP.NET Core 1.0 RTM ElasticsearchCrud
2016.05.20: Updated to ASP.NET Core 1.0 RC2 and ElasticsearchCrud dotnet RC2
2015.11.19: Updated to ASP.NET Core 1.0 RC1

Code: https://github.com/damienbod/AspNet5SearchWithElasticsearchCrud

To use Elasticsearch, add ElasticsearchCrud to the project.json file in the dependencies; “ElasticsearchCrud”: “2.3.3.1-beta3”

{
    "dependencies": {
        "Microsoft.NETCore.App": {
            "version": "1.0.0",
            "type": "platform"
        },
        "Microsoft.AspNetCore.Diagnostics": "1.0.0",
        "Microsoft.AspNetCore.Mvc": "1.0.0",
        "Microsoft.AspNetCore.Razor.Tools": {
            "version": "1.0.0-preview2-final",
            "type": "build"
        },
        "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
        "Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
        "Microsoft.AspNetCore.StaticFiles": "1.0.0",
        "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
        "Microsoft.Extensions.Configuration.Json": "1.0.0",
        "Microsoft.Extensions.Logging": "1.0.0",
        "Microsoft.Extensions.Logging.Console": "1.0.0",
        "Microsoft.Extensions.Logging.Debug": "1.0.0",
        "Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0",
        "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
        "ElasticsearchCrud": "2.3.3.1-beta2"
    },

    "tools": {
        "Microsoft.AspNetCore.Razor.Tools": {
            "version": "1.0.0-preview2-final",
            "imports": "portable-net45+win8+dnxcore50"
        },
        "Microsoft.AspNetCore.Server.IISIntegration.Tools": {
            "version": "1.0.0-preview2-final",
            "imports": "portable-net45+win8+dnxcore50"
        }
    },

    "frameworks": {
        "netcoreapp1.0": {
            "imports": [
                "dotnet5.6",
                "dnxcore50",
                "portable-net45+win8"
            ]
        }
    },

    "buildOptions": {
        "emitEntryPoint": true,
        "preserveCompilationContext": true
    },

    "runtimeOptions": {
        "gcServer": true
    },

    "publishOptions": {
        "include": [
            "wwwroot",
            "Views",
            "appsettings.json",
            "web.config"
        ]
    },

    "scripts": {
        "prepublish": [ "npm install", "bower install", "gulp clean", "gulp min" ],
        "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
    }
}

Here is a simple example of a search provider which implements a query_string query.

using System;
using System.Collections.Generic;
using System.Linq;

using ElasticsearchCRUD;
using ElasticsearchCRUD.Model.SearchModel;
using ElasticsearchCRUD.Model.SearchModel.Queries;

namespace AspNet5SearchWithElasticsearchCrud.Search
{
    public class ElasticSearchProvider : ISearchProvider, IDisposable
    {
        public ElasticSearchProvider()
        {
            _context = new ElasticsearchContext(ConnectionString, _elasticSearchMappingResolver);
        }

        private const string ConnectionString = "http://localhost:9200/";
        private readonly IElasticsearchMappingResolver _elasticSearchMappingResolver = new ElasticsearchMappingResolver();
        private readonly ElasticsearchContext _context;

        public IEnumerable<Skill> QueryString(string term)
        {
            var results = _context.Search<Skill>(BuildQueryStringSearch(term));
             return results.PayloadResult.Hits.HitsResult.Select(t => t.Source);
        }

        /*			
        {
          "query": {
                    "query_string": {
                       "query": "*"

                    }
                }
        }
         */
        private ElasticsearchCRUD.Model.SearchModel.Search BuildQueryStringSearch(string term)
        {
            var names = "";
            if (term != null)
            {
                names = term.Replace("+", " OR *");
            }

            var search = new ElasticsearchCRUD.Model.SearchModel.Search
            {
                Query = new Query(new QueryStringQuery(names + "*"))
            };

            return search;
        }

        public void AddUpdateEntity(Skill skill)
        {
            _context.AddUpdateDocument(skill, skill.Id);
            _context.SaveChanges();
        }

        public void UpdateSkill(long updateId, string updateName, string updateDescription)
        {
            var skill = _context.GetDocument<Skill>(updateId);
            skill.Updated = DateTime.UtcNow;
            skill.Name = updateName;
            skill.Description = updateDescription;
            _context.AddUpdateDocument(skill, skill.Id);
            _context.SaveChanges();
        }

        public void DeleteSkill(long deleteId)
        {
            _context.DeleteDocument<Skill>(deleteId);
            _context.SaveChanges();
        }

        private bool isDisposed;
        public void Dispose()
        {
            if (isDisposed)
            {
                isDisposed = true;
                _context.Dispose();
            }
        }
    }
}

The MVC 6 controller implements basic CRUD action methods using URL parameters.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace AspNet5SearchWithElasticsearchCrud.Controllers
{
    using AspNet5SearchWithElasticsearchCrud.Search;

    [Route("api/[controller]")]
    public class SearchController : Controller
    {
        readonly ISearchProvider _searchProvider;

        public SearchController(ISearchProvider searchProvider)
        {
            _searchProvider = searchProvider;
        }

        [HttpGet("{term}")]
        public IEnumerable<Skill> Search(string term)
        {
            return _searchProvider.QueryString(term);
        }

        [HttpPost("{id}/{name}/{description}")]
        public IActionResult Post(long id, string name, string description)
        {
            _searchProvider.AddUpdateEntity(
                new Skill
                    {
                        Created = DateTimeOffset.UtcNow,
                        Description = description,
                        Name = name,
                        Id = id
                    });

            string url = $"api/search/{id}/{name}/{description}";

            return Created(url, id);
        }

        [Microsoft.AspNet.Mvc.HttpPut("{id}/{updateName}/{updateDescription}")]
        public IActionResult Put(long id, string updateName, string updateDescription)
        {
            _searchProvider.UpdateSkill(id, updateName, updateDescription);

            return Ok();
        }


        // DELETE api/values/5
        [Microsoft.AspNet.Mvc.HttpDelete("{id}")]
        public IActionResult Delete(int id)
        {
            _searchProvider.DeleteSkill(id);

            return new NoContentResult();
        }
    }
}

A new Skill document can be added using Fiddler.
asp_net5ElasticsearchCrud_created_01

And can also be viewed using the search with a query term as a parameter in the URL.

asp_net5ElasticsearchCrud_search_02

Links:

https://www.elastic.co/downloads/elasticsearch

https://www.nuget.org/packages/ElasticsearchCRUD/2.3.3.1-beta2

https://github.com/damienbod/ElasticsearchCRUD

https://damienbod.com/2014/09/22/elasticsearch-crud-net-provider/

7 comments

  1. […] Using Elasticsearch with ASP.NET 5 dnxcore50 – damienbod […]

  2. […] USING ELASTICSEARCH WITH ASP.NET 5 DNXCORE50 […]

  3. Handy code example, thanks for posting it.

  4. Hello Damien,

    Thank you for providing elastic search library that targets core. are there any examples on the query builder.
    would like to know how to build most of the query example provided in below link.

    https://www.elastic.co/guide/en/elasticsearch/client/net-api/2.x/bool-queries.html.

    https://www.elastic.co/guide/en/elasticsearch/client/net-api/2.x/date-range-query-usage.html

    Coudnt make out how can i build complex query using bool or range or some complex joins.

    1. This is no DateRangeQuery in Elasticsearch just a range query which can be used for dates.

      https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-query.html

      I will just write a specific test to use this with dates

      https://github.com/damienbod/ElasticsearchCRUD/blob/master/src/ElasticsearchCrud/Model/SearchModel/Queries/RangeQuery.cs

      Greetings Damien

  5. Hi Nishank

    thanks, all implemented queries and filters have examples in the integration tests

    Here’s an example of a boolean query

    https://github.com/damienbod/ElasticsearchCRUD/blob/master/src/ElasticsearchCRUDNUnit.Integration.Test/SearchTests/SearchQueryQueryTests.cs

    I havn’t implemented the DateRangeQuery, only the RangeQuery and the DateRangeBucketAggregation.

    I’ll implement this next week, missed that…

    Greetings Damien

  6. Thank You Damien for providing me with the link.Its very helpful

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: