I managed to solve this by writing an extension method for the Stream class and implementing .NET Core's default behaviour for dealing with Span.
    public static int Read(this Stream thisStream, Span<byte> buffer)
    {
        byte[] sharedBuffer = ArrayPool<byte>.Shared.Rent(buffer.Length);
        try
        {
            int numRead = thisStream.Read(sharedBuffer, 0, buffer.Length);
            if ((uint)numRead > (uint)buffer.Length)
            {
                throw new IOException(SR.IO_StreamTooLong);
            }
            new Span<byte>(sharedBuffer, 0, numRead).CopyTo(buffer);
            return numRead;
        }
        finally { ArrayPool<byte>.Shared.Return(sharedBuffer); }
    }
and
    public static void Write(this Stream thisStream, ReadOnlySpan<byte> buffer)
    {
        byte[] sharedBuffer = ArrayPool<byte>.Shared.Rent(buffer.Length);
        try
        {
            buffer.CopyTo(sharedBuffer);
            thisStream.Write(sharedBuffer, 0, buffer.Length);
        }
        finally { ArrayPool<byte>.Shared.Return(sharedBuffer); }
    }