From Windows client to the database – step 1: create a WebAPI with .NET Core

There are lots of samples and answers to be found around creating WebAPI’s with ASP.NET, MVC etcetera. But I kept missing out on a simple walkthrough of (what I think is) a common scenario from start to finish. I have a database, and I want to give access to that data through a WebAPI with security enabled. Then I want to use that WebAPI from a Windows client. So I’m publishing a few posts now to write down the path I took using the latest, greatest.

The new development around websites on the server side is with ASP.NET 5 on .NET Core. The beauty of these new implementations is that they are open-source and cross-platform (Windows, MacOS and Linux). So you can use this technologie in the environment you like. As this is currently [March 2016] still in development, the documentation is still in development too. But it helped me to get started quickly. The documentation can be found on docs.asp.net.

As I wanted to use the latest as well for accessing the database, I chose to use EntityFramework 7. There is a very good walkthrough, both starting from code generating a database (code first) or starting with an existing database (Database first). As I started with an existing database, I chose the second one.

If you want to follow that approach but (as I did) want to start with a test database to understand the concept, use these steps to setup the Blogging database that will be used in this post as well. In the walkthrough of starting with an existing base you start with creating a Visual Studio solution with an ASP.NET website. I followed these steps to have a website as well.

From there I switched to the article Building your first Web API with MVC6. It’s very easy with ASP.NET 5 to have both a website and Web API controllers in your project. They use the same basics. The problem is that the building your first Web API document uses some fake data. I wanted to use the data from the database. So this is where I diverted from the sample.

Add a controller for the WebAPI

In the Controllers folder, I created a new controller called BlogApiController.cs using the Web API Controller Class template from the Add New Item dialog. You get a prepopulated class with the correct adornments to start with.

Next I added the BloggingContext and the appropriate constructor:


private BloggingContext _context;
public BlogApiController(BloggingContext context) { _context = context; }

Next step was to change the first Get method to retrieve all blogs. This was an easy one. As we want to return Blogs instead of strings, I changed the type to Blog. I use the same code for the webpage, so just return the complete list from the Blog table.


[HttpGet]
public IEnumerable<Blog> Get()
{
return _context.Blog.ToList();
}

Next step is the implementation of the Get of a specific blog with the given id. We’ve added a name to the HttpGet attribute – this is to enable ‘reroutes’ as we see used in the Post (Create) later. For this I changed the return type to IActionResult, as we also want to return HTTP errors when something is wrong. You need to wrap a record once found in an ObjectResult().


[HttpGet("{id}", Name = "GetBlog")]
public IActionResult Get(int id)
{
var item = _context.Blog.Where(x => x.BlogId == id).FirstOrDefault();
if (item == null)
{
return HttpNotFound();
}
return new ObjectResult(item);
}

Now we implement the Create of a blog entry (or a POST). For the post we also want to return errorcodes when something’s wrong. So we change the standard void type to an IActionResult. And instead of a string we get a Blog as parameter of course. We first check if the blog data was given. In the Add to the EF class optional declared Validators are run as well and can prevent the creation of the item. After we have saved the data with SaveChanges, we use a reroute to return the newly created item.

[HttpPost] public IActionResult Post([FromBody]Blog blog) { if (blog == null) return HttpBadRequest(); if (ModelState.IsValid) { _context.Blog.Add(blog); _context.SaveChanges(); return CreatedAtRoute("GetBlog", new { controller = "Blog", id = blog.BlogId }, blog); } return HttpBadRequest(); }
To update a record the PUT method is used. I’ve changed the return type to IActionResult again and pass in the Blog object. I also want to check if the update succeeded. If it failed because the requested record doesn’t exist (anymore), I want to return a NOT FOUND. If it succeeded, I don’t return anything.

[HttpPut]
public IActionResult Put([FromBody]Blog blog)
{
if (!ModelState.IsValid)
{
return HttpBadRequest();
try
{
_context.Update(blog);
_context.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
if (_context.Blog.FirstOrDefault(x => x.BlogId == blog.BlogId) == null)
{
return HttpNotFound();
}
else
{
throw;
}
}
return new NoContentResult();
}

The one left from CRUD is Delete. Again I changed the return type to an IActionResult and check if the required ID exists.

[HttpDelete("{id}")]
public IActionResult Delete(int id)
{
var item = _context.Blog.Where(x => x.BlogId == id).FirstOrDefault();
if (item == null)
{
return HttpNotFound();
}
_context.Blog.Remove(item);
_context.SaveChanges();
return new NoContentResult();
}

One method I wanted to add was a search. Now REST api’s only support GET, POST, PUT and DELETE. So how to add a custom method? I found answers in forums, but they were not using MVC6. But after some more research I found the solution. To have a call of the Search function with as parameter text to search for I’ve implemented the function below. I’ve added the Route() attribute to specify the custom url for this call. In this case it will be something like “http://localhost:12345/api/blogs/search/something” to search for the text “something”.


[Route("Search/{name}")]
[HttpGet("{name}")]
public IEnumerable<Blog> Search(string name)
{
return _context.Blog.Where(x => x.Url.Contains(name)).ToList();
}

Now you can query and execute CRUD operations on the blog entries in the database.

Next step: add authentication and authorization. This is for the next post.

 
Comments

No comments yet.