Returning non-FHIR content from a plugin

Some plugins may need to return content that is not a FHIR Resource. You currently cannot do that through the IVonkResponse. But there is another way. The component with order 1110 makes the IVonkContext accessible. The component with order 1120 turns the IVonkContext.Response to the HttpContext.Response. That means if you pick an order between 1110 and 1120 you can read the IVonkContext.Request and .Arguments, and write directly to the HttpContext.Response. The steps to take are:

  1. Configure your plugin with an order between 1110 and 1120
  2. Write the HttpContext.Response.Body directly
  3. Set other properties of the HttpContext.Response (like StatusCode) yourself.

An example of such a plugin would look like this. Note that this is now regular ASP.NET Core Middleware, not a service like in Template for a plugin.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using System.Text;
using System.Threading.Tasks;
using Vonk.Core.Context;
using Vonk.Core.Context.Features;
using Vonk.Core.Pluggability;

namespace com.mycompany.vonk.myplugin
{
    public class MyPluginMiddleware
    {
        private readonly RequestDelegate _next;

        public MyPluginMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task Invoke(HttpContext httpContext)
        {
            var vonkContext = httpContext.Vonk();
            var (request, args, _) = vonkContext.Parts();
            if (VonkInteraction.system_custom.HasFlag(request.Interaction))
            {
                //write something directly to the HttpContext.Response. Now you also have to set the Content-Type header and the Content-Length yourself.
                var message = "This is a response that is not a FHIR resource";
                string contentLength = Encoding.UTF8.GetByteCount(message).ToString();

                httpContext.Response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
                httpContext.Response.Headers.Add("Content-Length", contentLength);
                httpContext.Response.StatusCode = 200;
                await httpContext.Response.WriteAsync("This is a response that is not a FHIR resource");
            }
            else
            {
                await _next(httpContext);
            }
        }
    }

    [VonkConfiguration(order: 1115)] //note the order: between 1110 and 1120
    public static class MyPluginConfiguration
    {
        public static IServiceCollection AddMyPluginServices(IServiceCollection services)
        {
            //No services to register in this example, but if you create services to do the actual work - register them here.
            return services;
        }

        public static IApplicationBuilder UseMyPlugin(IApplicationBuilder app)
        {
            app.UseMiddleware<MyPluginMiddleware>(); //You cannot use the extension methods that allow you to filter the requests.
            return app;
        }
    }
}

Custom authorization plugin

This feature can also be used to implement custom authorization. You can find a template for that in this gist.

If you just return a statuscode, you may put the middleware anywhere in the pipeline. If you want to return e.g. a custom json object, you should put it between 1110 and 1120 as described above. Do not forget to set the Content-Type (to application/json for a custom json object).