Scott Hanselman

Using ASP.NET Core 2.1's HttpClientFactory with Refit's REST library

June 20, '18 Comments [11] Posted in ASP.NET | ASP.NET Web API | DotNetCore | Open Source
Sponsored By

Strong by Lucyb_22 used under Creative Commons from FlickrWhen I moved my podcast site over to ASP.NET Core 2.1 I also started using HttpClientFactory and wrote up my experience. It's a nice clean way to centralize both settings and policy for your HttpClients, especially if you're using a lot of them to talk to a lot of small services.

Last year I explored Refit, an automatic type-safe REST library for .NET Standard. It makes it super easy to just declare the shape of a client and its associated REST API with a C# interface:

public interface IGitHubApi
{
[Get("/users/{user}")]
Task<User> GetUser(string user);
}

and then ask for an HttpClient that speaks that API's shape, then call it. Fabulous.

var gitHubApi = RestService.For<IGitHubApi>("https://api.github.com");

var octocat = await gitHubApi.GetUser("octocat");

But! What does Refit look like and how does it work in an HttpClientFactory-enabled world? Refit has recently been updated with first class support for ASP.NET Core 2.1's HttpClientFactory with the Refit.HttpClientFactory package.

Since you'll want to centralize all your HttpClient configuration in your ConfigureServices method in Startup, Refit adds a nice extension method hanging off of Services.

You add a RefitClient of a type, then add whatever other IHttpClientBuilder methods you want afterwards:

services.AddRefitClient<IWebApi>()
.ConfigureHttpClient(c => c.BaseAddress = new Uri("https://api.example.com"));
// Add additional IHttpClientBuilder chained methods as required here:
// .AddHttpMessageHandler<MyHandler>()
// .SetHandlerLifetime(TimeSpan.FromMinutes(2));

Of course, then you can just have your HttpClient automatically created and passed into the constructor. You'll see in this sample from their GitHub that you get an IWebAPI (that is, whatever type you want, like my IGitHubApi) and just go to town with a strongly typed interfaces of an HttpClient with autocomplete.

public class HomeController : Controller
{
public HomeController(IWebApi webApi)
{
_webApi = webApi;
}

private readonly IWebApi _webApi;

public async Task<IActionResult> Index(CancellationToken cancellationToken)
{
var thing = await _webApi.GetSomethingWeNeed(cancellationToken);

return View(thing);
}
}

Refit is easy to use, and even better with ASP.NET Core 2.1. Go get Refit and try it today!

* Strong image by Lucyb_22 used under Creative Commons from Flickr


Sponsor: Check out dotMemory Unit, a free unit testing framework for fighting all kinds of memory issues in your code. Extend your unit testing with the functionality of a memory profiler.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

ASP.NET Core RESTful Web API versioning made easy

November 2, '16 Comments [29] Posted in ASP.NET Web API | Open Source
Sponsored By

Pic by WoCTechChat used under Creative Commons There's a LOT of interesting and intense arguments that have been made around how you should version your Web API. As soon as you say RESTful it turns into a religious argument where folks may just well quote from the original text. ;)

Regardless of how you personally version your Web APIs, and side-stepping any arguments one way or the other, there's great new repository by Chris Martinez that Jon Galloway turned me on to at https://github.com/Microsoft/aspnet-api-versioning. There's ASP.NET 4.x Web API, ODATA with ASP.NET Web APIs, and now ASP.NET Core 1.x. Fortunately Chris has assembled a nicely factored set of libraries called "ASP.NET API Versioning" that add service API versioning in a very convenient way.

As Chris points out:

The default API versioning configuration is compliant with the versioning semantics outlined by the Microsoft REST Guidelines. There are also a number of customization and extension points available to support transitioning services that may not have supported API versioning in the past or supported API versioning with semantics that are different from the Microsoft REST versioning guidelines.

It's also worth pointing out how great the documentation is given it's mostly a one-contributor project. I'm sure Chris would appreciate your help though, even if you're a first timer.

Chris has NuGet packages for three flavors of Web APIs on ASP.NET:

But you should really clone the repo and check out his excellent samples.

When versioning services there's a few schools of thought and with ASP.NET Core it's super easy to get started:

public void ConfigureServices( IServiceCollection services )
{
services.AddMvc();
services.AddApiVersioning();

// remaining other stuff omitted for brevity
}

Oh, but you already have an API that's not versioned yet?

services.AddApiVersioning(
o =>
{
o.AssumeDefaultVersionWhenUnspecified = true );
o.DefaultApiVersion = new ApiVersion( new DateTime( 2016, 7, 1 ) );
} );

Your versions can look however'd you like them to:

  • /api/foo?api-version=1.0
  • /api/foo?api-version=2.0-Alpha
  • /api/foo?api-version=2015-05-01.3.0
  • /api/v1/foo
  • /api/v2.0-Alpha/foo
  • /api/v2015-05-01.3.0/foo

QueryString Parameter Versioning

I'm not a fan of this one, but here's the general idea:

[ApiVersion( "2.0" )]
[Route( "api/helloworld" )]
public class HelloWorld2Controller : Controller {
[HttpGet]
public string Get() => "Hello world!";
}

So this means to get 2.0 over 1.0 in another Controller with the same route, you'd go here:

/api/helloworld?api-version=2.0

Also, don't worry, you can use namespaces to have multiple HelloWorldControllers without having to have any numbers in the class names. ;)

URL Path Segment Versioning

This happens to be my first choice (yes I know Headers are "better," more on that later). You put the version in the route like this.

Here we're throwing in a little curveball. There's three versions but just two controllers.

[ApiVersion( "1.0" )]
[Route( "api/v{version:apiVersion}/[controller]" )]
public class HelloWorldController : Controller {
public string Get() => "Hello world!";
}

[ApiVersion( "2.0" )]
[ApiVersion( "3.0" )]
[Route( "api/v{version:apiVersion}/helloworld" )]
public class HelloWorld2Controller : Controller {
[HttpGet]
public string Get() => "Hello world v2!";

[HttpGet, MapToApiVersion( "3.0" )]
public string GetV3() => "Hello world v3!";
}

To be clear, you have total control, but the result from the outside is quite clean with /api/v[1|2|3]/helloworld. In fact, you can see with this example where this is more sophisticated than what you can do with routing out of the box. (I know some of you are thinking "meh I'll just make a route table." I think the semantics are much clearer and cleaner this way.

Header Versioning

Or, the hardest way (and the one that a lot of people this is best, but I disagree) is HTTP Headers. Set this up in ConfigureServices for ASP.NET Core:

public void ConfigureServices( IServiceCollection services )
{
services.AddMvc();
services.AddApiVersioning(o => o.ApiVersionReader = new HeaderApiVersionReader("api-version"));
}

When you do HeaderApiVersioning you won't be able to just do a GET in your browser, so I'll use Postman to add the header (or I could use Curl, or WGet, or PowerShell, or a Unit Test):

image

Deprecating

Speaking of semantics, here's a nice one. Let's say an API is going away in the next 6 months.

[ApiVersion( "2.0" )]
[ApiVersion( "1.0", Deprecated = true )]

This advertises that 1.0 is going away soon and that folks should consider 2.0. Where does it advertise this fact? The response headers!

api-supported-versions: 2.0, api-deprecated-versions: 1.0

All in all, this is very useful stuff and I'm happy to add it to my personal toolbox. Should this be built in? I don't know but I sure appreciate that it exists.

SIDE NOTE: There is/was the start of a VersionRoute over in the AspNet.Mvc repo. Maybe these folks need to join forces?

How do YOU version your Web APIs and Services?


Sponsor: Big thanks to Telerik! They recently launched their UI toolset for ASP.NET Core so feel free to check it out or learn more about ASP.NET Core development in their recent whitepaper.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Exploring a minimal WebAPI with ASP.NET Core

July 26, '16 Comments [12] Posted in ASP.NET | ASP.NET Web API
Sponsored By

They are still working on the "dotnet new" templates, but you can also get cool templates from "yo aspnet" usingn Yeoman. The generator-aspnet package for Yeoman includes an empty web app, a console app, a few web app flavors, test projects, and a very simple Web API application that returns JSON and generally tries to be RESTful.

yo aspnet

The startup.cs is pretty typical and basic. The Startup constructor sets up the Configuration with an appsettings.json file and add a basic Console logger. Then by calling "UseMvc()" we get to use all ASP.NET Core which includes both centralized routing and attribute routing. ASP.NET Core's controllers are unified now, so there isn't a "Controller" and "ApiController" base class. It's just Controller. Controllers that return JSON or those that return Views with HTML are the same so they get to share routes and lots of functionality.

public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}

public IConfigurationRoot Configuration { get; }

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();

app.UseMvc();
}
}

Then you can make a basic controller and use Attribute Routing to do whatever makes you happy. Just by putting [HttpGet] on a method makes that method the /api/Values default for a simple GET.

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

namespace tinywebapi.Controllers
{
[Route("api/[controller]")]
public class ValuesController : Controller
{
// GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}

// GET api/values/5
[HttpGet("{id}")]
public string Get(int id)
{
return "value";
}

// POST api/values
[HttpPost]
public void Post([FromBody]string value)
{
}

// PUT api/values/5
[HttpPut("{id}")]
public void Put(int id, [FromBody]string value)
{
}

// DELETE api/values/5
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
}

If we run this with "dotnet run" and call/curl/whatever to http://localhost:5000/api/Values we'd get a JSON array of two values by default. How would we (gasp!) add XML as a formatting/serialization option that would respond to a request with an Accept: application/xml header set?

I'll add "Microsoft.AspNetCore.Mvc.Formatters.Xml" to project.json and then add one method to ConfigureServices():

services.AddMvc()
        .AddXmlSerializerFormatters();

Now when I go into Postman (or curl, etc) and do a GET with Accept: application/xml as a header, I'll get the same object expressed as XML. If I ask for JSON, I'll get JSON.

 Postman is a great way to explore WebAPIs

If I like, I can create my own custom formatters and return whatever makes me happy. PDFs, vCards, even images.

Next post I'm going to explore the open source NancyFx framework and how to make minimal WebAPI using Nancy under .NET Core.


Sponsor: Thanks to Aspose for sponsoring the feed this week! Aspose makes programming APIs for working with files, like: DOC, XLS, PPT, PDF and countless more.  Developers can use their products to create, convert, modify, or manage files in almost any way. Aspose is a good company and they offer solid products. Check them out, and download a free evaluation!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

NuGet Package of the Week: Microphone registers and discovers Web APIs and REST services with Consul

October 27, '15 Comments [9] Posted in ASP.NET Web API | NuGetPOW | Open Source
Sponsored By

I'm sitting on a plane on the way back from a lovely time in Europe. I attended and spoke at some great conferences and met some cool people - some of which you'll hear on the podcast soon. Anyway, one of the things that I heard mentioned by attendees more than once was the issue of (micro) service discovery for RESTful APIs. Now if you lived through the WS*.* years you'll perhaps feel a lot of this is familiar or repeated territory, but the new stuff definitely fits together more effortlessly than in the past.

Consul is a system that does service discovery, configuration management, and health checking for your services. You can write Web APIs in lots of things, Rails, Python, and ASP.NET with WebAPI or NancyFX.

Microphone is a library by Roger Johansson that plugs into both WebAPI and Nancy and very simply and easily registers your services with Consul. It's recently been expanded to support CoreOs-ETCD as well, so it's really a general purpose framework.

I made a little .NET 4.6 console app that self hosts a WebAPI like this.

namespace ConsulSelfHostedWebAPIService
{
class Program
{
static void Main(string[] args)
{
Cluster.Bootstrap(new WebApiProvider(), new ConsulProvider(), "HanselWebApiService", "v1");
Console.ReadLine();
}
}

public class DefaultController : ApiController
{
public string Get()
{
return "Hey it's my personal WebApi Service";
}
}
}

Now my Web API is registered with Consul, and now Consul itself is a RESTful Web API where I can hit http://localhost:8500/v1/agent/services and get a list of registered services. It's the Discovery Service.

Consul reporting my WebAPI

Then later in a client or perhaps another Web API, I can ask for it by name and I'll get back the address and port that it's on, then call it.

var instance = await Cluster.FindServiceInstanceAsync("Heycool");

return String.Format("Look there's a service at {0}:{1}", instance.Address, instance.Port);

Here's an active debug session showing the address and port in the instance:

Using Microphone.WebAPI and Consul for Service Discovery

It will be interesting to see what will happen with Consul and systems like it if the Azure Service Fabric gains traction. Service Fabric offers a lot more, but I wonder if there is a use case for both, with Service Fabric managing lifecycles and Consul doing discovery.

This is all early days, but it's interesting. What do you think about these new discovery services for Web APIs?


Sponsor: Big thanks to Infragistics for sponsoring the feed this week. Quickly & effortlessly create advanced, stylish, & high performing UIs for ASP.NET MVC with Ignite UI. Leverage the full power of Infragistics’ JavaScript-based jQuery/HTML5 control suite today.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

NuGet Package of the Week: ASP.NET Web API Caching with CacheCow and CacheOutput

June 27, '14 Comments [8] Posted in ASP.NET Web API | NuGet | NuGetPOW
Sponsored By

You can see other cool NuGet Packages I've mentioned on the blog here. Today's NuGet package is CacheCow, which has possibly the coolest Open Source Library name since Lawnchair.js.

image

"CacheCow is a library for implementing HTTP caching on both client and server in ASP.NET Web API. It uses message handlers on both client and server to intercept request and response and apply caching logic and rules."

CacheCow was started by Ali Kheyrollahi with help from Tugberk Ugurlu and the community, and is a fantastically useful piece of work. I wouldn't be surprised to see this library start showing in more places one day.

As an aside, Ali, this would be a great candidate for setting up a free AppVeyor Continuous Integration build along with a badge showing that the project is building and healthy!

CacheCow on the server can manage the cache in a number of ways. You can store it in SQL Server with the EntityTagStore, or implement your own storage handler. You can keep the cache in memcached, Redis, etc.

Consider using a library like CacheCow if you're putting together a Web API and haven't given sufficient thought to caching yet, or if you're already sprinkling cache code throughout your business logic. You might already suspect that is going to litter your code but perhaps haven't gotten around to tidying up. Now is a good time to unify your caching.

As a very simple example, here's the HTTP Headers from an HTTP GET to a Web API:

Cache-Control: no-cache
Content-Length: 19
Content-Type: application/json; charset=utf-8
Date: Fri, 27 Jun 2014 23:22:10 GMT
Expires: -1
Pragma: no-cache

Here's the same thing after adding the most basic caching to my ASP.NET applications config:

GlobalConfiguration.Configuration.MessageHandlers.Add(new CachingHandler(GlobalConfiguration.Configuration));

The HTTP Headers with the same GET with CacheCow enabled:

Cache-Control: no-transform, must-revalidate, max-age=0, private
Content-Length: 19
Content-Type: application/json; charset=utf-8
Date: Fri, 27 Jun 2014 23:24:16 GMT
ETag: W/"e1c5ab4f818f4cde9426c6b0824afe5b"
Last-Modified: Fri, 27 Jun 2014 23:24:16 GMT

Notice the Cache-Control header, the Last-Modified, and the ETag. The ETag is weak as indicted by "W/" which means that this response is semantically equivalent to the last response. If I was caching persistently, I could get a strong ETag indicating that the cached response was byte-for-byte identical. Also, if the client was smart about caching and added If-Modified-Since or If-None-Match for ETags, the response might be a 304 Not Modified, rather than a 200 OK. If you're going to add caching to your Web API server, you'll want to make sure your clients respect those headers fully!

From ALI's blog, you can still use HttpClient in your clients, but you use WebRequestHandler as the message handler:

HttpClient client = new HttpClient(new WebRequestHandler()
{
CachePolicy = new RequestCachePolicy(RequestCacheLevel.Default)
});
var httpResponseMessage = await client.GetAsync(http://superpoopy);

Really don't want a resource cached? Remember, this is HTTP so, Cache-Control: no-cache from the client!

Of course, one of the most important aspects of caching anything is "when do I invalidate the cache?" CacheCow gives you a lot control over this, but you really need to be aware of what your actual goal is or you'll find things cache you don't want, or things not cached that you do.

  • Are you looking for time-based caching? Cache for 5 min after a DB access?
  • Are you looking for smart caching that invalidates when it sees what could be a modification? Invalidate a collection after a POST/PUT/DELETE?

Given that you're likely using REST, you'll want to make sure that the semantics of these caching headers and their intent is reflected in your behavior. Last-Modified should reflect realty when possible.

From the CacheCow Wiki, there's great features for both the Server-side and Client-side. Here's CacheCow.Server features

  • Managing ETag, Last Modified, Expires and other cache related headers
  • Implementing returning Not-Modified 304 and precondition failed 412 responses for conditional calls
  • Invalidating cache in case of PUT, POST, PATCH and DELETE
  • Flexible resource organization. Rules can be defined so invalidation of a resource can invalidate linked resources

and the CacheCow.Client features

  • Caching GET responses according to their caching headers
  • Verifying cached items for their staleness
  • Validating cached items if must-revalidate parameter of Cache-Control header is set to true. It will use ETag or Expires whichever exists
  • Making conditional PUT for resources that are cached based on their ETag or expires header, whichever exists

Another good ASP.NET caching library to explore is ASP.NET Web API "CacheOutput" by Filip Wojcieszyn. While it doesn't have an fun to say name ;) it's got some great features and is super easy to get started with. You can find CacheOutput with NuGet at

Install-Package Strathweb.CacheOutput.WebApi2

And you'll configure your caching options using the intuitive CacheOutput attributes like those you may have seen in ASP.NET MVC:

[CacheOutput(ClientTimeSpan = 100, ServerTimeSpan = 100)]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}

ASP.NET Web API CacheOutput has great getting started docs and clear easy to ready code.

So, you've got options. Go explore!

You can also pickup the Pro ASP.NET Web API book at Amazon. Go explore CacheCow or CacheOutput and support open source! If you find issues or feel there's work to be done in the documentation, why not do it and submit a pull request? I'm sure any project would appreciate some help with updated samples, quickstarts, or better docs.


Sponsor: Many thanks to our friends at Octopus Deploy for sponsoring the feed this week. Did you know that NuGet.org deploys with Octopus? Using NuGet and powerful conventions, Octopus Deploy makes it easy to automate releases of ASP.NET applications and Windows Services. Say goodbye to remote desktop and start automating today!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb
Page 1 of 3 in the ASP.NET Web API category Next Page

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.